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
This commit is contained in:
Daniel Arantes Loverde
2026-06-03 15:49:26 -03:00
parent c89c80e8d1
commit 2d27240cee

View File

@@ -301,57 +301,74 @@ struct CheckoutView: View {
.font(AppTypography.overline) .font(AppTypography.overline)
.foregroundStyle(sectionTitleColor) .foregroundStyle(sectionTitleColor)
VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 0) {
paymentGroupCard( // Toggle row
title: "Pagar Pelo App", HStack(spacing: 12) {
subtitle: "Mais rápido e seguro", VStack(alignment: .leading, spacing: 2) {
isSelected: useInAppPayment Text(useInAppPayment ? "Pagar Pelo App" : "Pagar Na Maquininha")
) { .font(AppTypography.heading3)
VStack(spacing: 0) { .foregroundStyle(AppColors.textPrimary)
ForEach(availableInAppPaymentMethods, id: \.rawValue) { method in Text(useInAppPayment ? "Mais rápido e seguro" : "Na entrega/retirada com a loja")
paymentRow(method, isInAppGroup: true) .font(.caption)
if method != availableInAppPaymentMethods.last { .foregroundStyle(AppColors.textMuted)
Divider() }
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: { .labelsHidden()
useInAppPayment = true .tint(AppColors.primary)
if availableInAppPaymentMethods.contains(paymentMethod) == false {
paymentMethod = .pix
}
} }
.padding(14)
paymentGroupCard( Divider()
title: "Pagar Na Maquininha Da Loja", .padding(.horizontal, 14)
subtitle: "Pague na entrega/retirada com os métodos aceitos pela loja",
isSelected: useInAppPayment == false // 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 { if availableStoreMachineMethods.isEmpty {
Text("Loja não informou métodos presenciais.") Text("Loja não informou métodos presenciais.")
.font(AppTypography.body) .font(AppTypography.body)
.foregroundStyle(AppColors.textMuted) .foregroundStyle(AppColors.textMuted)
.padding(.horizontal, 14) .padding(14)
.padding(.bottom, 14)
} else { } else {
VStack(spacing: 0) { ForEach(availableStoreMachineMethods, id: \.rawValue) { method in
ForEach(availableStoreMachineMethods, id: \.rawValue) { method in paymentRow(method, isInAppGroup: false)
paymentRow(method, isInAppGroup: false) if method != availableStoreMachineMethods.last {
if method != availableStoreMachineMethods.last { Divider().padding(.horizontal, 14)
Divider()
}
} }
} }
} }
} 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 return method.subtitle
} }
private func paymentGroupCard<Content: View>(
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 { private var bottomBar: some View {
VStack(spacing: 12) { VStack(spacing: 12) {