From 2d27240cee1dce820e654bcc953122231f46cce9 Mon Sep 17 00:00:00 2001 From: Daniel Arantes Loverde Date: Wed, 3 Jun 2026 15:49:26 -0300 Subject: [PATCH] feat(checkout): replace dual payment group cards with single toggle switch Toggle ON = Pagar Pelo App (default), shows in-app methods (PIX, Credit Card) Toggle OFF = Pagar Na Maquininha, shows store machine methods Automatically resets paymentMethod on toggle switch Removes paymentGroupCard helper, saves vertical space --- .../PediFoods/Views/Main/CheckoutView.swift | 129 ++++++++---------- 1 file changed, 54 insertions(+), 75 deletions(-) diff --git a/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift b/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift index 2399d09..3f03913 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/CheckoutView.swift @@ -301,57 +301,74 @@ struct CheckoutView: View { .font(AppTypography.overline) .foregroundStyle(sectionTitleColor) - VStack(alignment: .leading, spacing: 12) { - paymentGroupCard( - title: "Pagar Pelo App", - subtitle: "Mais rápido e seguro", - isSelected: useInAppPayment - ) { - VStack(spacing: 0) { - ForEach(availableInAppPaymentMethods, id: \.rawValue) { method in - paymentRow(method, isInAppGroup: true) - if method != availableInAppPaymentMethods.last { - Divider() + VStack(alignment: .leading, spacing: 0) { + // Toggle row + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 2) { + Text(useInAppPayment ? "Pagar Pelo App" : "Pagar Na Maquininha") + .font(AppTypography.heading3) + .foregroundStyle(AppColors.textPrimary) + Text(useInAppPayment ? "Mais rápido e seguro" : "Na entrega/retirada com a loja") + .font(.caption) + .foregroundStyle(AppColors.textMuted) + } + Spacer() + Toggle("", isOn: Binding( + get: { useInAppPayment }, + set: { newValue in + withAnimation(.easeInOut(duration: 0.2)) { + useInAppPayment = newValue + if newValue { + if availableInAppPaymentMethods.contains(paymentMethod) == false { + paymentMethod = .pix + } + } else { + guard availableStoreMachineMethods.isEmpty == false else { + useInAppPayment = true + return + } + if availableStoreMachineMethods.contains(paymentMethod) == false, + let first = availableStoreMachineMethods.first { + paymentMethod = first + } + } } } - } - } onTap: { - useInAppPayment = true - if availableInAppPaymentMethods.contains(paymentMethod) == false { - paymentMethod = .pix - } + )) + .labelsHidden() + .tint(AppColors.primary) } + .padding(14) - paymentGroupCard( - title: "Pagar Na Maquininha Da Loja", - subtitle: "Pague na entrega/retirada com os métodos aceitos pela loja", - isSelected: useInAppPayment == false - ) { + Divider() + .padding(.horizontal, 14) + + // Methods list + if useInAppPayment { + ForEach(availableInAppPaymentMethods, id: \.rawValue) { method in + paymentRow(method, isInAppGroup: true) + if method != availableInAppPaymentMethods.last { + Divider().padding(.horizontal, 14) + } + } + } else { if availableStoreMachineMethods.isEmpty { Text("Loja não informou métodos presenciais.") .font(AppTypography.body) .foregroundStyle(AppColors.textMuted) - .padding(.horizontal, 14) - .padding(.bottom, 14) + .padding(14) } else { - VStack(spacing: 0) { - ForEach(availableStoreMachineMethods, id: \.rawValue) { method in - paymentRow(method, isInAppGroup: false) - if method != availableStoreMachineMethods.last { - Divider() - } + ForEach(availableStoreMachineMethods, id: \.rawValue) { method in + paymentRow(method, isInAppGroup: false) + if method != availableStoreMachineMethods.last { + Divider().padding(.horizontal, 14) } } } - } onTap: { - guard availableStoreMachineMethods.isEmpty == false else { return } - useInAppPayment = false - if availableStoreMachineMethods.contains(paymentMethod) == false, - let first = availableStoreMachineMethods.first { - paymentMethod = first - } } } + .background(AppColors.surface) + .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) } } @@ -405,44 +422,6 @@ struct CheckoutView: View { return method.subtitle } - private func paymentGroupCard( - title: String, - subtitle: String, - isSelected: Bool, - @ViewBuilder content: () -> Content, - onTap: @escaping () -> Void - ) -> some View { - VStack(alignment: .leading, spacing: 10) { - HStack(spacing: 10) { - VStack(alignment: .leading, spacing: 2) { - Text(title) - .font(AppTypography.heading3) - .foregroundStyle(AppColors.textPrimary) - Text(subtitle) - .font(.caption) - .foregroundStyle(AppColors.textMuted) - } - Spacer() - Circle() - .stroke(isSelected ? AppColors.tertiary : AppColors.textMuted.opacity(0.45), lineWidth: 2) - .frame(width: 22, height: 22) - .background( - Circle() - .fill(isSelected ? AppColors.tertiary : Color.clear) - ) - } - .padding(.horizontal, 14) - .padding(.top, 14) - .appContentShape(Rectangle()) - .onTapGesture(perform: onTap) - - content() - .allowsHitTesting(isSelected) - .opacity(isSelected ? 1 : 0.82) - } - .background(AppColors.surface) - .clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)) - } private var bottomBar: some View { VStack(spacing: 12) {