[2026-07-resubmission] Add guest browsing flow with App Attest session for App Review resubmission

Adds a pre-login public store locator (guest session via DeviceCheck/App
Attest, keychain-backed token storage) so the app no longer forces sign-in
before showing any content, plus updated support URL metadata.
This commit is contained in:
Daniel Arantes Loverde
2026-07-30 11:35:25 -03:00
parent 3e93196b92
commit 017bd7168f
21 changed files with 1140 additions and 136 deletions

View File

@@ -135,4 +135,62 @@ extension HomeView {
}
return "Não foi possível carregar os estabelecimentos."
}
/// Anonymous store loading: no account, no coordinates just the
/// manually-picked state/city from the public locator. The BFF endpoint
/// has no category filter, so any category chip selection is applied
/// client-side via `filteredStores` (HomeView+Filtering.swift), same as
/// the multi-select filters already do.
@MainActor
func loadGuestStores(hadExistingStores: Bool, category: String?, refreshCategories: Bool) async {
guard let state = GuestLocationStore.shared.selectedState,
let city = GuestLocationStore.shared.selectedCity else {
isLoadingStores = false
stores = []
storesError = "Escolha um estado e cidade para visualizar os estabelecimentos."
appState.activeModal = .addressPicker
return
}
do {
let items = try await PublicLocationService.shared.fetchStores(state: state, city: city)
isLoadingStores = false
let mapped = items.map(StoreSummary.init(publicItem:))
stores = mapped
if refreshCategories || (category == nil && categories.count <= 1) {
await loadHomeCategories(withFallbackStores: mapped, forceRefresh: refreshCategories)
if categories.contains(where: { $0.id == selectedCategory }) == false {
selectedCategory = "all"
}
}
storesError = nil
} catch {
if isCancelledRequest(error) {
isLoadingStores = false
return
}
isLoadingStores = false
reportStoresLoadFailure(storesUserMessage(error), hadExistingStores: hadExistingStores)
}
}
}
extension StoreSummary {
/// Maps the public-locator DTO onto the same model HomeView already
/// renders distance/positiveReviews don't exist in that response.
init(publicItem: PublicStoreListItem) {
self.id = publicItem.id
self.name = publicItem.name ?? "Loja"
self.logo = publicItem.logo
self.cover = publicItem.cover
self.category = publicItem.category
self.rating = publicItem.rating
self.reviewsCount = publicItem.totalReviews
self.positiveReviews = nil
self.deliveryTime = publicItem.deliveryTime
self.deliveryFee = publicItem.deliveryFee
self.distance = nil
self.isOpen = publicItem.isOpen
self.statusLabel = publicItem.statusLabel
}
}