[public-store-distance] Consume the public distance contract, stop labelling it as unavailable

Guest browsing showed 'Distância indisponível' on every store card and a
'--' tile on store detail, because the public locator response carries no
distance and StoreSummary.init(publicItem:) hardcoded nil.

Backend contract (docs/plans/public-store-distance-consumer.md): distance
is a number, never null, 0 means unavailable. Implemented app-side ahead of
the backend - every change is forward-compatible, and the part that removes
the broken label works with no backend at all.

- PublicStoreListItem / PublicStoreDetail: + distance (optional, so today's
  responses without the field still decode).
- StoreSummary.init(publicItem:): normalize the 0 sentinel to nil, so one
  representation of 'unknown' reaches the label and the max-distance filter.
- fetchStoreDetail: send state/city from GuestLocationStore by default -
  the server needs them to resolve the city centroid.
- formatDistance: empty string for nil/0/negative. It previously returned
  'Distância indisponível' for nil, and - found by the new test - '0 m' for
  0 and '-1000 m' for a negative.
- StoreCard: drop the distance segment and its '·' separator together,
  otherwise the row ended in a dangling separator.
- StoreDetailView: drop the DISTÂNCIA tile and its divider instead of '--'.

Also fixes the same label in the authenticated flow when the user declined
location and has no address coordinates.

Tests: PublicStoreDistanceTests (decode with/without the field, passthrough,
0 normalization) + the empty case in HomeViewFilteringTests.
This commit is contained in:
Daniel Arantes Loverde
2026-08-27 16:33:01 -03:00
parent 0f0672f18d
commit a0e4375914
10 changed files with 154 additions and 33 deletions

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -79,9 +79,10 @@
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */; };
7D7BF04765D6CA6AC4F11DDD /* StoreCatalogNormalizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EC38EEE1E7105BC21E354C /* StoreCatalogNormalizerTests.swift */; };
80B476CCE2B90BEE2FA4CB37 /* PediFoodsUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56E3E6C1834786CA3621B7BB /* PediFoodsUITestsLaunchTests.swift */; };
811217F88AA350A70CC22479 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
811217F88AA350A70CC22479 /* NotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
85EA52253BABA327EC07CFF0 /* AuthFormattersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 561E00C486D60EC2DF720EAF /* AuthFormattersTests.swift */; };
8D6622AE9325D02B830BD115 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */; };
901A6A5A00C18FC59F764B85 /* PublicStoreDistanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */; };
90ADA376585F5438F3A1A1D6 /* HomeView+Favorites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1517B141263438E466452037 /* HomeView+Favorites.swift */; };
918BCBC1EAD7EE134DB9742D /* CheckoutTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FF15CEE5B137074E6B2489 /* CheckoutTypesTests.swift */; };
926E0C4DD3C82485D4262A62 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B2F3558C58CD1E71F0F3A0 /* ContentView.swift */; };
@@ -168,7 +169,7 @@
dstPath = "";
dstSubfolderSpec = 13;
files = (
811217F88AA350A70CC22479 /* NotificationService.appex in Embed Foundation Extensions */,
811217F88AA350A70CC22479 /* NotificationServiceExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -210,6 +211,7 @@
4C415019CC1F314EE7318864 /* ApiCardModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCardModelsTests.swift; sourceTree = "<group>"; };
4DC5416AEBA77C43CF55ABA8 /* PublicLocationPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicLocationPickerView.swift; sourceTree = "<group>"; };
4E0CCEF22D356F9EC723999D /* HomeView+Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeView+Data.swift"; sourceTree = "<group>"; };
4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicStoreDistanceTests.swift; sourceTree = "<group>"; };
507E868458359BE0E4FF25F1 /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; };
52BFF93F21509F1AD4F6676B /* PediFoodsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PediFoodsApp.swift; sourceTree = "<group>"; };
54795EDED987426386226358 /* GuestLocationStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestLocationStoreTests.swift; sourceTree = "<group>"; };
@@ -228,7 +230,7 @@
69A9FB3DE679C3D4C60E7E42 /* ApiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiConfig.swift; sourceTree = "<group>"; };
6BF467DF1447525F04B242B0 /* ReviewsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewsView.swift; sourceTree = "<group>"; };
6CAA9B253B1A6C8815A0E69D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PediFoodsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PediFoodsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6EC381D02A37312BE360024F /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
6FC454261845C1EDF970552A /* CheckoutTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutTypes.swift; sourceTree = "<group>"; };
7034E89267D9F5D86BF1E424 /* CartCheckoutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartCheckoutFlowTests.swift; sourceTree = "<group>"; };
@@ -241,7 +243,7 @@
76B24E69A3F6A3EB86449870 /* AddAddressFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAddressFormView.swift; sourceTree = "<group>"; };
794249487F718BCFBF176E8D /* ApiModelsDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiModelsDecodingTests.swift; sourceTree = "<group>"; };
79D2854B8062D96742CFDD99 /* HomeViewComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewComponents.swift; sourceTree = "<group>"; };
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PediFoods.app; sourceTree = BUILT_PRODUCTS_DIR; };
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = PediFoods.app; sourceTree = BUILT_PRODUCTS_DIR; };
7A9F14B1BDD7747C546DFAF0 /* GuestSessionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuestSessionService.swift; sourceTree = "<group>"; };
7C13751F450A42A2BDB0783D /* ProfileLoggedOutFlowTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileLoggedOutFlowTests.swift; sourceTree = "<group>"; };
7CD06F9A7AF9365D1FBE35D0 /* AddressComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressComponents.swift; sourceTree = "<group>"; };
@@ -250,7 +252,7 @@
89B662E8B7E1B8F1CF7E657E /* KeychainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = "<group>"; };
8A3FB85A2A2E2952B9A2BAB0 /* DeepLinkDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkDestination.swift; sourceTree = "<group>"; };
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegalDocumentTests.swift; sourceTree = "<group>"; };
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PediFoodsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = PediFoodsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8D2C6A0E85E133F947293181 /* OrderDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsView.swift; sourceTree = "<group>"; };
8DD2B73D89E6D33643EF58F5 /* DeepLinkRouteEffectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkRouteEffectTests.swift; sourceTree = "<group>"; };
8E3A0A2E253ABFCA35D02F28 /* TextFieldCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldCompat.swift; sourceTree = "<group>"; };
@@ -285,7 +287,7 @@
C44662BAA20AD862BE1DBC40 /* PublicLocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicLocationService.swift; sourceTree = "<group>"; };
C4745C12F14B695C77DFE178 /* SnackbarOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarOverlay.swift; sourceTree = "<group>"; };
C6B08901A67C8D90A3B50882 /* ApiCustomerPayloadModelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCustomerPayloadModelsTests.swift; sourceTree = "<group>"; };
C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
CA44F5384D21B7F718F95522 /* StoreDetailSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreDetailSupport.swift; sourceTree = "<group>"; };
CAB9F980426D39E93E091051 /* LocationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationService.swift; sourceTree = "<group>"; };
CD5EE81AE4347B4086684F8B /* CartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartView.swift; sourceTree = "<group>"; };
@@ -344,7 +346,7 @@
126A579C448C784867DC3AB1 /* Products */ = {
isa = PBXGroup;
children = (
C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */,
C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */,
7A6D74FD2D2F2F79349EA04E /* PediFoods.app */,
6DD1D8390E57439A347F9E07 /* PediFoodsTests.xctest */,
8AF987AB319512C123DFD558 /* PediFoodsUITests.xctest */,
@@ -446,6 +448,7 @@
23B6B814027518969EB04341 /* HomeViewFilteringTests.swift */,
5A82497C63D507E82FE02693 /* ImageSourceResolverTests.swift */,
8AA914FB8B32B106911FD67B /* LegalDocumentTests.swift */,
4E55893DD92CBFB24F212454 /* PublicStoreDistanceTests.swift */,
747AD255B6D881E011FDF907 /* SessionStateStoreTests.swift */,
160571AB2F8D4DF98C0BE16F /* SmokeTests.swift */,
B2CE116C585A7529CF309B3D /* SnackbarCenterTests.swift */,
@@ -621,7 +624,7 @@
);
name = NotificationServiceExtension;
productName = NotificationServiceExtension;
productReference = C724E02EC34BB1D4352C2FF0 /* NotificationService.appex */;
productReference = C724E02EC34BB1D4352C2FF0 /* NotificationServiceExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
66486D25E3A8A75EA8FACE44 /* PediFoodsUITests */ = {
@@ -671,10 +674,21 @@
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
3027BAE353B414EC70E2A2AC = {
DevelopmentTeam = "";
ProvisioningStyle = Manual;
};
33EB2407F0F758EB98A769D3 = {
DevelopmentTeam = "";
ProvisioningStyle = Manual;
};
66486D25E3A8A75EA8FACE44 = {
DevelopmentTeam = K4E5BZMM4V;
TestTargetID = B3B5CFF77A8ED019D1299ABB;
};
B3B5CFF77A8ED019D1299ABB = {
DevelopmentTeam = "";
ProvisioningStyle = Manual;
SystemCapabilities = {
com.apple.Push = {
enabled = YES;
@@ -867,6 +881,7 @@
63AB40542AABCC3CB2390B87 /* HomeViewFilteringTests.swift in Sources */,
22E3BF78B8C2B22D14EABE8B /* ImageSourceResolverTests.swift in Sources */,
2FCB3403A764AD74AC3BD47C /* LegalDocumentTests.swift in Sources */,
901A6A5A00C18FC59F764B85 /* PublicStoreDistanceTests.swift in Sources */,
F760557D906B860D0EA277DE /* SessionStateStoreTests.swift in Sources */,
B24B898508C8A8EF4191EC89 /* SmokeTests.swift in Sources */,
7CC171B83BC4CDEC38B25F8C /* SnackbarCenterTests.swift in Sources */,
@@ -986,7 +1001,6 @@
388EFAF707AD295240B9E951 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APP_ATTEST_ENVIRONMENT = production;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
@@ -994,7 +1008,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2026.0.25.0.0.1;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
ENABLE_PREVIEWS = YES;
@@ -1002,7 +1016,7 @@
INFOPLIST_FILE = PediFoods/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Pedi Foods";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods usa sua localização para mostrar lojas perto de você";
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods uses your location to show nearby stores and estimate delivery times.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = NO;
@@ -1031,7 +1045,6 @@
4424276379B7A6A98892CFBC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APP_ATTEST_ENVIRONMENT = development;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
@@ -1039,7 +1052,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2026.0.25.0.0.1;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = K4E5BZMM4V;
ENABLE_PREVIEWS = YES;
@@ -1047,7 +1060,7 @@
INFOPLIST_FILE = PediFoods/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Pedi Foods";
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods usa sua localização para mostrar lojas perto de você";
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "PediFoods uses your location to show nearby stores and estimate delivery times.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = NO;