feat(cards): add input masks and char limits to card form fields
- Card number: groups of 4 digits (0000 0000 0000 0000), max 16 digits - Expiry: MM/AAAA mask, max 6 digits - CVV: digits only, max 4 - CPF: 000.000.000-00 mask, max 11 digits - canSubmit validates stripped digit counts
This commit is contained in:
@@ -997,10 +997,10 @@ struct PaymentCardView: View {
|
||||
}
|
||||
|
||||
var canSubmit: Bool {
|
||||
holderName.isEmpty == false &&
|
||||
holderName.trimmingCharacters(in: .whitespaces).isEmpty == false &&
|
||||
cardNumber.filter(\.isNumber).count >= 13 &&
|
||||
expiry.count >= 4 &&
|
||||
cvv.count >= 3 &&
|
||||
expiry.filter(\.isNumber).count == 6 &&
|
||||
cvv.filter(\.isNumber).count >= 3 &&
|
||||
cpf.filter(\.isNumber).count == 11
|
||||
}
|
||||
|
||||
@@ -1051,15 +1051,49 @@ struct PaymentCardView: View {
|
||||
VStack(spacing: 10) {
|
||||
labeledField("Número do Cartão", placeholder: "0000 0000 0000 0000", text: $cardNumber)
|
||||
.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..<end])
|
||||
}.joined(separator: " ")
|
||||
if masked != v { cardNumber = masked }
|
||||
}
|
||||
|
||||
labeledField("Nome no Cartão", placeholder: "Como impresso no cartão", text: $holderName)
|
||||
|
||||
HStack(spacing: 10) {
|
||||
labeledField("Validade", placeholder: "MM/AAAA", text: $expiry)
|
||||
.keyboardType(.numberPad)
|
||||
.onChange(of: expiry) { _, v in
|
||||
let d = String(v.filter(\.isNumber).prefix(6))
|
||||
let masked: String
|
||||
if d.count <= 2 { masked = d }
|
||||
else { masked = "\(d.prefix(2))/\(d.dropFirst(2))" }
|
||||
if masked != v { expiry = masked }
|
||||
}
|
||||
|
||||
labeledField("CVV", placeholder: "•••", text: $cvv)
|
||||
.keyboardType(.numberPad)
|
||||
.onChange(of: cvv) { _, v in
|
||||
let d = String(v.filter(\.isNumber).prefix(4))
|
||||
if d != v { cvv = d }
|
||||
}
|
||||
}
|
||||
|
||||
labeledField("CPF do Titular", placeholder: "000.000.000-00", text: $cpf)
|
||||
.keyboardType(.numberPad)
|
||||
.onChange(of: cpf) { _, v in
|
||||
let d = String(v.filter(\.isNumber).prefix(11))
|
||||
let masked: String
|
||||
if d.count <= 3 { masked = d }
|
||||
else if d.count <= 6 { masked = "\(d.prefix(3)).\(d.dropFirst(3))" }
|
||||
else if d.count <= 9 { masked = "\(d.prefix(3)).\(d.dropFirst(3).prefix(3)).\(d.dropFirst(6))" }
|
||||
else { masked = "\(d.prefix(3)).\(d.dropFirst(3).prefix(3)).\(d.dropFirst(6).prefix(3))-\(d.dropFirst(9))" }
|
||||
if masked != v { cpf = masked }
|
||||
}
|
||||
}
|
||||
.padding(14)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user