import SwiftUI #if canImport(LCEssentials) && os(iOS) import LCEssentials #endif #if canImport(UIKit) import UIKit #endif struct StoreDetailView: View { let storeId: String let storeName: String let storeCoverURL: String? let storeLogoURL: String? let storeCategory: String? let storeRating: Double? let storeDistance: String? let storeDeliveryFee: Double? @Binding var appState: AppState @Environment(\.dismiss) var dismiss @State var isLoading = true @State var errorMessage: String? = nil @State var info: StoreInfoResult? = nil @State var categories: [StoreCatalogCategory] = [] @State var selectedCategoryId: String? = nil @State var selectedProduct: StoreCatalogProduct? = nil @State var selectedPizzaCategoryId: String? = nil @State var showSwitchStoreAlert = false @State var pendingCartItem: CartItemState? = nil @State var pendingProductSheet: StoreCatalogProduct? = nil @State var pendingPizzaCategoryId: String? = nil @State var pendingCartAction: CartAction = .add @State var didLoad = false @State var categoryHeaderOffsets: [String: CGFloat] = [:] @State var isProgrammaticCategoryScroll = false @State var isFavoriteRequestInFlight = false @State var scrollOffset: CGFloat = 0 var isCategoryTabsPinned: Bool { scrollOffset >= topSectionHeight } var stretchAmount: CGFloat { max(0, -scrollOffset) } let cardTopInset: CGFloat = 180 let summaryCardBaseHeight: CGFloat = 212 let closedBannerHeight: CGFloat = 44 let coverVisibleUntilY: CGFloat = 253 let storeLogoSize: CGFloat = 84 var body: some View { ScrollViewReader { proxy in ScrollView(showsIndicators: false) { ScrollOffsetReader(offsetY: $scrollOffset) LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) { topSection Section { sectionedProducts } header: { categoryTabs(proxy: proxy, isPinned: isCategoryTabsPinned) } } } .coordinateSpace(name: StoreDetailScrollCoordinateSpace.name) .refreshable { await loadStoreData(forceRefresh: true) } .ignoresSafeArea(edges: .top) .background(AppColors.backgroundLight) .saturation(isStoreOpen ? 1 : 0) } .navigationBarBackButtonHidden(true) .appHiddenNavigationBar() .task { guard didLoad == false else { return } didLoad = true await loadStoreData(forceRefresh: false) } .sheet(item: $selectedProduct) { product in NavigationStack { ProductDetailSheet( product: product, imageURL: resolvedURL(product.image), storeId: storeId, currentQuantityForItemId: { itemId in currentQuantity(forCartItemId: itemId) }, onAdd: { item in guard isStoreOpen else { SnackbarCenter.shared.show(title: "Loja fechada no momento.", style: .warning, icon: "moon.zzz.fill", duration: 2.0) return } requestSetCartItem(item) } ) } } .sheet( isPresented: Binding( get: { selectedPizzaCategoryId != nil }, set: { isPresented in if isPresented == false { selectedPizzaCategoryId = nil } } ) ) { if let category = categories.first(where: { $0.id == selectedPizzaCategoryId }) { NavigationStack { PizzaProductDetailSheet( category: category, storeId: storeId, resolveImageURL: { raw in resolvedURL(raw) }, currentQuantityForItemId: { itemId in currentQuantity(forCartItemId: itemId) }, onAdd: { item in guard isStoreOpen else { SnackbarCenter.shared.show(title: "Loja fechada no momento.", style: .warning, icon: "moon.zzz.fill", duration: 2.0) return } requestSetCartItem(item) } ) } } else { ProgressView() } } .alert("Trocar de loja?", isPresented: $showSwitchStoreAlert) { Button("Cancelar", role: .cancel) { pendingCartItem = nil pendingProductSheet = nil pendingPizzaCategoryId = nil } Button("Limpar carrinho e adicionar", role: .destructive) { appState.cart.clear() switch pendingCartAction { case .add: guard let pendingCartItem else { return } applyAddToCart(pendingCartItem) case .set: guard let pendingCartItem else { return } applySetCartItem(pendingCartItem) case .openProductSheet: guard let pendingProductSheet else { return } selectedProduct = pendingProductSheet case .openPizzaSheet: guard let pendingPizzaCategoryId else { return } selectedPizzaCategoryId = pendingPizzaCategoryId } self.pendingCartItem = nil self.pendingProductSheet = nil self.pendingPizzaCategoryId = nil } } message: { Text("Seu carrinho tem itens de outra loja. Deseja limpar o carrinho atual para adicionar este produto?") } .onPreferenceChange(CategoryHeaderOffsetPreferenceKey.self) { offsets in categoryHeaderOffsets = offsets syncCategoryWithScroll() } } }