This commit is contained in:
Daniel Arantes Loverde
2026-04-16 14:50:07 -03:00
parent 7f7d414e6c
commit 0ebb854213
20 changed files with 871 additions and 216 deletions

View File

@@ -1,11 +1,15 @@
import SwiftUI
extension StoreDetailView {
func heroIconButton(icon: String, action: @escaping () -> Void) -> some View {
func heroIconButton(
icon: String,
foregroundStyle: Color = .white,
action: @escaping () -> Void
) -> some View {
Button(action: action) {
Image(systemName: icon)
.font(.system(size: 14, weight: .semibold))
.foregroundStyle(Color.white)
.foregroundStyle(foregroundStyle)
.frame(width: 32, height: 32)
.background(Color.white.opacity(0.24))
.clipShape(Circle())
@@ -65,6 +69,49 @@ extension StoreDetailView {
info?.isOpen ?? true
}
var isFavoriteStore: Bool {
appState.favorites.storeIds.contains(storeId)
}
@MainActor
func toggleFavoriteStore() async {
guard isFavoriteRequestInFlight == false else { return }
guard appState.session.isAuthenticated else {
SnackbarCenter.shared.show(title: "Faça login para favoritar lojas.", style: .warning, icon: "person.crop.circle.badge.exclamationmark", duration: 2.5)
return
}
let isFavorite = isFavoriteStore
isFavoriteRequestInFlight = true
defer { isFavoriteRequestInFlight = false }
do {
let response = try await ApiService().setStoreFavorite(storeId: storeId, isFavorite: isFavorite == false)
guard response.error == false, let result = response.result else {
let message = response.message ?? "Não foi possível atualizar seus favoritos."
SnackbarCenter.shared.show(title: message, style: .error, icon: "xmark.octagon.fill", duration: 3.5)
return
}
appState.favorites.storeIds = Set(result.favorites)
let successTitle = isFavorite
? "\(storeName) removida dos favoritos."
: "\(storeName) adicionada aos favoritos."
let successIcon = isFavorite ? "heart.slash.fill" : "heart.fill"
SnackbarCenter.shared.show(title: successTitle, style: .success, icon: successIcon, duration: 2.2)
} catch {
let message: String
if let networkError = error as? NetworkError {
message = networkError.errorDescription ?? "Não foi possível atualizar seus favoritos."
} else if let serviceError = error as? ApiServiceError {
message = serviceError.errorDescription ?? "Não foi possível atualizar seus favoritos."
} else {
message = "Não foi possível atualizar seus favoritos."
}
SnackbarCenter.shared.show(title: message, style: .error, icon: "xmark.octagon.fill", duration: 3.5)
}
}
var summaryCardHeight: CGFloat {
summaryCardBaseHeight + (isStoreOpen ? 0 : closedBannerHeight)
}
@@ -97,9 +144,13 @@ extension StoreDetailView {
if forceRefresh == false,
let cachedInfo: StoreInfoResult = AppContentCache.shared.value(for: infoCacheKey, as: StoreInfoResult.self),
let cachedCatalog: [StoreCatalogCategory] = AppContentCache.shared.value(for: catalogCacheKey, as: [StoreCatalogCategory].self) {
let normalizedCatalog = StoreCatalogNormalizer.sanitize(categories: cachedCatalog, storeId: storeId)
info = cachedInfo
categories = cachedCatalog
selectedCategoryId = cachedCatalog.first?.id
categories = normalizedCatalog
selectedCategoryId = StoreCatalogNormalizer.preferredCategoryId(
from: normalizedCatalog,
preferredId: selectedCategoryId
)
isLoading = false
return
}
@@ -110,9 +161,9 @@ extension StoreDetailView {
}
do {
async let infoRequest = ApiService().storeInfo(storeId: storeId)
async let catalogRequest = ApiService().storeCatalog(storeId: storeId)
let (infoResponse, catalogResponse) = try await (infoRequest, catalogRequest)
let apiService = ApiService()
let infoResponse = try await apiService.storeInfo(storeId: storeId)
let catalogResponse = try await apiService.storeCatalog(storeId: storeId)
if infoResponse.error {
errorMessage = infoResponse.message ?? "Não foi possível carregar a loja."
@@ -125,13 +176,21 @@ extension StoreDetailView {
return
}
let normalizedCatalog = StoreCatalogNormalizer.sanitize(
categories: catalogResponse.result ?? [],
storeId: storeId
)
info = infoResponse.result
categories = catalogResponse.result ?? []
selectedCategoryId = categories.first?.id
categories = normalizedCatalog
selectedCategoryId = StoreCatalogNormalizer.preferredCategoryId(
from: normalizedCatalog,
preferredId: selectedCategoryId
)
if let info = infoResponse.result {
AppContentCache.shared.set(info, for: infoCacheKey, ttl: AppCacheTTL.twoHours)
}
AppContentCache.shared.set(categories, for: catalogCacheKey, ttl: AppCacheTTL.twoHours)
AppContentCache.shared.set(normalizedCatalog, for: catalogCacheKey, ttl: AppCacheTTL.twoHours)
isLoading = false
} catch {
isLoading = false