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,51 +301,32 @@ 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)
}
}
}
} onTap: {
useInAppPayment = true
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
}
}
paymentGroupCard(
title: "Pagar Na Maquininha Da Loja",
subtitle: "Pague na entrega/retirada com os métodos aceitos pela loja",
isSelected: useInAppPayment == false
) {
if availableStoreMachineMethods.isEmpty {
Text("Loja não informou métodos presenciais.")
.font(AppTypography.body)
.foregroundStyle(AppColors.textMuted)
.padding(.horizontal, 14)
.padding(.bottom, 14)
} else {
VStack(spacing: 0) {
ForEach(availableStoreMachineMethods, id: \.rawValue) { method in
paymentRow(method, isInAppGroup: false)
if method != availableStoreMachineMethods.last {
Divider()
guard availableStoreMachineMethods.isEmpty == false else {
useInAppPayment = true
return
}
}
}
}
} onTap: {
guard availableStoreMachineMethods.isEmpty == false else { return }
useInAppPayment = false
if availableStoreMachineMethods.contains(paymentMethod) == false,
let first = availableStoreMachineMethods.first {
paymentMethod = first
@@ -353,6 +334,42 @@ struct CheckoutView: View {
}
}
}
))
.labelsHidden()
.tint(AppColors.primary)
}
.padding(14)
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(14)
} else {
ForEach(availableStoreMachineMethods, id: \.rawValue) { method in
paymentRow(method, isInAppGroup: false)
if method != availableStoreMachineMethods.last {
Divider().padding(.horizontal, 14)
}
}
}
}
}
.background(AppColors.surface)
.clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous))
}
}
private func paymentRow(_ method: CheckoutPaymentMethod, isInAppGroup: Bool) -> some View {
@@ -405,44 +422,6 @@ struct CheckoutView: View {
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 {
VStack(spacing: 12) {