diff --git a/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift b/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift index 21774b4..fef09e7 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift @@ -929,89 +929,93 @@ struct CardSelectionSheet: View { } var body: some View { - VStack(spacing: 0) { - // Header - HStack { - Text("Selecionar Cartão") - .font(AppTypography.heading2) - .foregroundStyle(AppColors.textPrimary) - Spacer() - Button { - dismiss() - } label: { - Image(systemName: "xmark") - .font(.system(size: 12, weight: .bold)) - .foregroundStyle(AppColors.textMuted) - .frame(width: 30, height: 30) - .background(AppColors.surface) - .clipShape(Circle()) - } - .buttonStyle(.plain) - } - .padding(.horizontal, 20) - .padding(.top, 20) - .padding(.bottom, 16) - - ScrollView(showsIndicators: false) { - VStack(alignment: .leading, spacing: 16) { - if savedCards.isEmpty == false { - VStack(alignment: .leading, spacing: 0) { - ForEach(savedCards) { card in - savedCardRow(card) - if card.id != savedCards.last?.id { - Divider().padding(.horizontal, 14) - } - } - } - .background(AppColors.surface) - .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) - - if let selectedCardId { - PrimaryButton(title: isSubmitting ? "Processando..." : "Pagar \(formatCurrency(cardContext.total))") { - guard isSubmitting == false else { return } - onSavedCardConfirmed(selectedCardId) - } - .disabled(isSubmitting) - } - - Text("ou") - .font(AppTypography.caption) - .foregroundStyle(AppColors.textMuted) - .frame(maxWidth: .infinity, alignment: .center) - } - + ZStack(alignment: .top) { + VStack(spacing: 0) { + // Header + HStack { + Text("Selecionar Cartão") + .font(AppTypography.heading2) + .foregroundStyle(AppColors.textPrimary) + Spacer() Button { - showNewCardSheet = true + dismiss() } label: { - HStack(spacing: 10) { - Image(systemName: "plus.circle.fill") - .font(.system(size: 18)) - .foregroundStyle(AppColors.primary) - Text("Adicionar novo cartão") - .font(AppTypography.heading3) - .foregroundStyle(AppColors.primary) - Spacer() - } - .padding(14) - .background(AppColors.surface) - .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) + Image(systemName: "xmark") + .font(.system(size: 12, weight: .bold)) + .foregroundStyle(AppColors.textMuted) + .frame(width: 30, height: 30) + .background(AppColors.surface) + .clipShape(Circle()) } .buttonStyle(.plain) } .padding(.horizontal, 20) - .padding(.bottom, 32) - } - } - .background(AppColors.backgroundLight) - .sheet(isPresented: $showNewCardSheet) { - PaymentCardView( - context: cardContext, - appState: $appState, - onOrderCreated: { orderId, shortId in - showNewCardSheet = false - onOrderCreated(orderId, shortId) + .padding(.top, 20) + .padding(.bottom, 16) + + ScrollView(showsIndicators: false) { + VStack(alignment: .leading, spacing: 16) { + if savedCards.isEmpty == false { + VStack(alignment: .leading, spacing: 0) { + ForEach(savedCards) { card in + savedCardRow(card) + if card.id != savedCards.last?.id { + Divider().padding(.horizontal, 14) + } + } + } + .background(AppColors.surface) + .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) + + if let selectedCardId { + PrimaryButton(title: isSubmitting ? "Processando..." : "Pagar \(formatCurrency(cardContext.total))") { + guard isSubmitting == false else { return } + onSavedCardConfirmed(selectedCardId) + } + .disabled(isSubmitting) + } + + Text("ou") + .font(AppTypography.caption) + .foregroundStyle(AppColors.textMuted) + .frame(maxWidth: .infinity, alignment: .center) + } + + Button { + showNewCardSheet = true + } label: { + HStack(spacing: 10) { + Image(systemName: "plus.circle.fill") + .font(.system(size: 18)) + .foregroundStyle(AppColors.primary) + Text("Adicionar novo cartão") + .font(AppTypography.heading3) + .foregroundStyle(AppColors.primary) + Spacer() + } + .padding(14) + .background(AppColors.surface) + .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) + } + .buttonStyle(.plain) + } + .padding(.horizontal, 20) + .padding(.bottom, 32) } - ) + } + .background(AppColors.backgroundLight) + .sheet(isPresented: $showNewCardSheet) { + PaymentCardView( + context: cardContext, + appState: $appState, + onOrderCreated: { orderId, shortId in + showNewCardSheet = false + onOrderCreated(orderId, shortId) + } + ) + } + + SnackbarOverlay(center: SnackbarCenter.shared) } } @@ -1133,140 +1137,144 @@ struct PaymentCardView: View { } var body: some View { - VStack(spacing: 0) { - HStack { - Text("Novo Cartão") - .font(AppTypography.heading2) - .foregroundStyle(AppColors.textPrimary) - Spacer() - Button { - dismiss() - } label: { - Image(systemName: "xmark") - .font(.system(size: 12, weight: .bold)) - .foregroundStyle(AppColors.textMuted) - .frame(width: 30, height: 30) - .background(AppColors.surface) - .clipShape(Circle()) - } - .buttonStyle(.plain) - } - .padding(.horizontal, 20) - .padding(.top, 20) - .padding(.bottom, 16) - - ScrollView(showsIndicators: false) { - VStack(alignment: .leading, spacing: 16) { - // Total + ZStack(alignment: .top) { + VStack(spacing: 0) { HStack { - VStack(alignment: .leading, spacing: 2) { - Text("Total do Pedido") - .font(AppTypography.caption) - .foregroundStyle(AppColors.textMuted) - Text(formatCurrency(context.total)) - .font(AppTypography.heading2) - .foregroundStyle(AppColors.textPrimary) - } + Text("Novo Cartão") + .font(AppTypography.heading2) + .foregroundStyle(AppColors.textPrimary) Spacer() + Button { + dismiss() + } label: { + Image(systemName: "xmark") + .font(.system(size: 12, weight: .bold)) + .foregroundStyle(AppColors.textMuted) + .frame(width: 30, height: 30) + .background(AppColors.surface) + .clipShape(Circle()) + } + .buttonStyle(.plain) } - .padding(14) - .background(AppColors.surface) - .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) + .padding(.horizontal, 20) + .padding(.top, 20) + .padding(.bottom, 16) - // Dados do cartão - VStack(alignment: .leading, spacing: 0) { - sectionHeader("DADOS DO CARTÃO") - VStack(spacing: 10) { - labeledField("Número do Cartão", placeholder: "0000 0000 0000 0000", text: $cardNumber, brandLogo: detectedBrandLogo) - .keyboardType(.numberPad) - .onChange(of: cardNumber) { _, v in - let d = String(v.filter(\.isNumber).prefix(16)) - let masked = stride(from: 0, to: d.count, by: 4) - .map { i -> String in - let start = d.index(d.startIndex, offsetBy: i) - let end = d.index(start, offsetBy: min(4, d.count - i)) - return String(d[start.. String in + let start = d.index(d.startIndex, offsetBy: i) + let end = d.index(start, offsetBy: min(4, d.count - i)) + return String(d[start.. String in let s = d.index(d.startIndex, offsetBy: i); let e = d.index(s, offsetBy: min(4, d.count - i)); return String(d[s.. String in let s = d.index(d.startIndex, offsetBy: i); let e = d.index(s, offsetBy: min(4, d.count - i)); return String(d[s..