import Foundation import SwiftUI struct CartView: View { @Binding var appState: AppState @State var openCheckout = false @State var couponCode = "" @State var appliedCouponCode: String? = nil @State var discountValue: Double = 0 @State var deliveryFee: Double = 5 var body: some View { ScrollView(showsIndicators: false) { VStack(spacing: 16) { Text("Meu Carrinho") .font(AppTypography.heading1) .foregroundStyle(AppColors.textPrimary) .frame(maxWidth: .infinity, alignment: .center) .padding(.top, 20) if appState.cart.items.isEmpty { VStack(spacing: 10) { Text("Seu carrinho está vazio") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) Text("Adicione produtos para continuar.") .font(AppTypography.body) .foregroundStyle(AppColors.textMuted) } .frame(maxWidth: .infinity, minHeight: 280, alignment: .center) } else { VStack(spacing: 12) { ForEach(appState.cart.items) { item in cartItemRow(item) } } .padding(.horizontal, 20) couponSection .padding(.horizontal, 20) summarySection .padding(.horizontal, 20) } } .padding(.bottom, 120) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(AppColors.backgroundLight) .navigationDestination(isPresented: $openCheckout) { CheckoutView(appState: $appState) } } private var subtotalValue: Double { appState.cart.items.reduce(0) { $0 + (Double($1.quantity) * $1.unitPrice) } } private var totalValue: Double { max(0, subtotalValue + deliveryFee - discountValue) } private var couponSection: some View { VStack(alignment: .leading, spacing: 10) { Text("Cupom de Desconto") .font(AppTypography.heading2) .foregroundStyle(AppColors.textPrimary) HStack(spacing: 10) { HStack(spacing: 8) { Image(systemName: "ticket") .foregroundStyle(AppColors.textMuted) TextField("Inserir cupom", text: $couponCode) .appNoAutoCap() } .padding(.horizontal, 12) .frame(height: 50) .background(AppColors.surface) .overlay( RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous) .stroke(AppColors.brandSoft, lineWidth: 1) ) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) Button("Aplicar") { applyCoupon() } .font(AppTypography.heading3) .foregroundStyle(AppColors.textInverse) .frame(width: 120, height: 50) .background(AppColors.brandDark) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) .buttonStyle(.plain) } if let appliedCouponCode { Text("Cupom aplicado: \(appliedCouponCode)") .font(.caption) .foregroundStyle(AppColors.primary) } } } private var summarySection: some View { VStack(alignment: .leading, spacing: 12) { Text("Resumo de Valores") .font(AppTypography.heading2) .foregroundStyle(AppColors.textPrimary) summaryRow(title: "Subtotal", value: formatCurrency(subtotalValue)) summaryRow(title: "Taxa de Entrega", value: formatCurrency(deliveryFee)) summaryRow(title: "Desconto", value: "-\(formatCurrency(discountValue))", valueColor: Color.red) Divider() summaryRow(title: "Total", value: formatCurrency(totalValue), highlighted: true) Button { openCheckout = true } label: { HStack(spacing: 10) { Text("Ir para o Pagamento") .font(AppTypography.heading2) Image(systemName: "arrow.right") .font(.system(size: 18, weight: .bold)) } .foregroundStyle(AppColors.textInverse) .frame(maxWidth: .infinity, minHeight: 54) .background(AppColors.primary) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } .buttonStyle(.plain) } .padding(16) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusXL, style: .continuous)) } private func summaryRow(title: String, value: String, valueColor: Color? = nil, highlighted: Bool = false) -> some View { HStack { Text(title) .font(highlighted ? AppTypography.heading2 : AppTypography.body) .foregroundStyle(AppColors.textMuted) Spacer() Text(value) .font(highlighted ? AppTypography.heading1 : AppTypography.heading3) .foregroundStyle(valueColor ?? AppColors.textPrimary) } } private func cartItemRow(_ item: CartItemState) -> some View { HStack(spacing: 14) { AsyncStoreImage(imageURL: item.imageURL) .frame(width: 78, height: 78) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) VStack(alignment: .leading, spacing: 6) { Text(item.name) .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) .lineLimit(1) if let details = item.details, details.isEmpty == false { Text(details) .font(.caption) .foregroundStyle(AppColors.textMuted) .lineLimit(2) } Text(formatCurrency(item.unitPrice)) .font(AppTypography.body) .foregroundStyle(AppColors.textMuted) } Spacer() HStack(spacing: 10) { Button(action: { appState.cart.decrement(itemId: item.id) }) { Image(systemName: "minus") .font(.system(size: 13, weight: .bold)) .foregroundStyle(AppColors.textPrimary) .frame(width: 32, height: 32) .background(AppColors.backgroundLight) .clipShape(Circle()) } .buttonStyle(.plain) Text("\(item.quantity)") .font(AppTypography.heading3) .foregroundStyle(AppColors.textPrimary) .frame(minWidth: 18) Button(action: { appState.cart.increment(itemId: item.id) }) { Image(systemName: "plus") .font(.system(size: 13, weight: .bold)) .foregroundStyle(AppColors.textPrimary) .frame(width: 32, height: 32) .background(AppColors.tertiary) .clipShape(Circle()) } .buttonStyle(.plain) } .padding(.horizontal, 8) .padding(.vertical, 6) .background(AppColors.backgroundLight) .clipShape(Capsule()) } .padding(.horizontal, 12) .padding(.vertical, 12) .background(AppColors.surface) .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } private func applyCoupon() { let normalized = couponCode.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() guard normalized.isEmpty == false else { appliedCouponCode = nil discountValue = 0 return } if normalized == "DESCONTO10" { appliedCouponCode = normalized discountValue = min(subtotalValue, subtotalValue * 0.1) return } appliedCouponCode = nil discountValue = 0 } private func formatCurrency(_ value: Double) -> String { String(format: "R$ %.2f", value).replacingOccurrences(of: ".", with: ",") } }