payment and list

This commit is contained in:
Daniel Arantes Loverde
2026-02-24 10:19:47 -03:00
parent 3a3dc7217b
commit ca83a275ac
51 changed files with 1645 additions and 256 deletions

View File

@@ -7,7 +7,9 @@ struct CartView: View {
@State var couponCode = ""
@State var appliedCouponCode: String? = nil
@State var discountValue: Double = 0
@State var deliveryFee: Double = 5
@State var deliveryFee: Double? = nil
@State var selectedCustomerAddress: CustomerAddress? = nil
@State var isLoadingDeliveryFee = false
var body: some View {
ScrollView(showsIndicators: false) {
@@ -50,6 +52,9 @@ struct CartView: View {
.navigationDestination(isPresented: $openCheckout) {
CheckoutView(appState: $appState)
}
.task(id: deliveryFeeWatchKey) {
await refreshDeliveryFee()
}
}
private var subtotalValue: Double {
@@ -57,7 +62,16 @@ struct CartView: View {
}
private var totalValue: Double {
max(0, subtotalValue + deliveryFee - discountValue)
max(0, subtotalValue + (deliveryFee ?? 0) - discountValue)
}
private var deliveryFeeWatchKey: String {
let storeId = appState.cart.storeId ?? "nil"
let selectedId = appState.address.selectedId ?? "nil"
let display = appState.address.display.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
let lat = appState.address.latitude.map { String(format: "%.5f", $0) } ?? "nil"
let lng = appState.address.longitude.map { String(format: "%.5f", $0) } ?? "nil"
return "\(storeId)|\(selectedId)|\(display)|\(lat)|\(lng)"
}
private var couponSection: some View {
@@ -108,7 +122,7 @@ struct CartView: View {
.foregroundStyle(AppColors.textPrimary)
summaryRow(title: "Subtotal", value: formatCurrency(subtotalValue))
summaryRow(title: "Taxa de Entrega", value: formatCurrency(deliveryFee))
summaryRow(title: "Taxa de Entrega", value: deliveryFeeLabel)
summaryRow(title: "Desconto", value: "-\(formatCurrency(discountValue))", valueColor: Color.red)
Divider()
@@ -136,6 +150,16 @@ struct CartView: View {
.clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusXL, style: .continuous))
}
private var deliveryFeeLabel: String {
if isLoadingDeliveryFee {
return "Calculando..."
}
if let deliveryFee {
return formatCurrency(deliveryFee)
}
return "Indisponível"
}
private func summaryRow(title: String, value: String, valueColor: Color? = nil, highlighted: Bool = false) -> some View {
HStack {
Text(title)
@@ -230,4 +254,88 @@ struct CartView: View {
private func formatCurrency(_ value: Double) -> String {
String(format: "R$ %.2f", value).replacingOccurrences(of: ".", with: ",")
}
@MainActor
private func refreshDeliveryFee() async {
guard appState.cart.items.isEmpty == false else {
deliveryFee = nil
selectedCustomerAddress = nil
return
}
guard let storeId = appState.cart.storeId, storeId.isEmpty == false else {
deliveryFee = nil
selectedCustomerAddress = nil
return
}
isLoadingDeliveryFee = true
defer { isLoadingDeliveryFee = false }
do {
let profileResponse = try await ApiService().profile()
let addresses = profileResponse.result?.addressBook ?? []
if let selectedId = appState.address.selectedId, selectedId.isEmpty == false {
selectedCustomerAddress = addresses.first(where: { $0.id == selectedId })
} else {
selectedCustomerAddress = nil
}
if selectedCustomerAddress == nil {
let display = appState.address.display
.trimmingCharacters(in: .whitespacesAndNewlines)
.lowercased()
if display.isEmpty == false, display != "defina seu endereco" {
selectedCustomerAddress = addresses.first {
($0.label ?? "").trimmingCharacters(in: .whitespacesAndNewlines).lowercased() == display
}
}
}
if selectedCustomerAddress == nil {
selectedCustomerAddress = addresses.first
}
if let selected = selectedCustomerAddress {
appState.address.selectedId = selected.id
let label = (selected.label ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if label.isEmpty == false {
appState.address.display = label
}
if let lat = selected.latLong?.first, let lng = selected.latLong?.dropFirst().first {
appState.address.latitude = lat
appState.address.longitude = lng
}
SessionStateStore.saveAddress(appState.address)
}
let payloadLat = selectedCustomerAddress?.latLong?.first ?? appState.address.latitude
let payloadLng = selectedCustomerAddress?.latLong?.dropFirst().first ?? appState.address.longitude
let payload = ValidateDeliveryAddressPayload(
address: ValidateDeliveryAddressDataPayload(
street: selectedCustomerAddress?.address,
number: selectedCustomerAddress?.number,
neighborhood: selectedCustomerAddress?.neighborhood,
city: selectedCustomerAddress?.city,
state: selectedCustomerAddress?.state,
zip: selectedCustomerAddress?.zipCode,
lat: payloadLat,
lng: payloadLng
)
)
let validationResponse = try await ApiService().validateDeliveryAddress(storeId: storeId, payload: payload)
guard validationResponse.error == false,
validationResponse.result?.deliveryAllowed == true,
let fee = validationResponse.result?.deliveryFee else {
deliveryFee = nil
return
}
deliveryFee = fee
} catch {
deliveryFee = nil
}
}
}