fixed credit card issues with formatting for different card types also added an min/max length based on card type.

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-06-06 12:22:21 -05:00
parent f5380532ff
commit 2e46759857

View File

@ -9,7 +9,20 @@ import Foundation
import UIKit
extension InputField {
class CreditCardNumberRule: Rule, Withable {
var cardType: CreditCardType?
var errorMessage: String = "You have exceeded the character limit."
func isValid(value: String?) -> Bool {
guard let count = value?.count, let min = cardType?.minLength, let max = cardType?.maxLength else { return true }
if min == max {
return count == max
} else {
return count >= min && count <= max
}
}
}
public enum CreditCardType: String, CaseIterable {
case generic
case visa
@ -38,15 +51,22 @@ extension InputField {
}
}
var separatorIndices: [Int] {
func separatorIndices(_ length: Int) -> [Int] {
var indices: [Int] = [4, 8, 12]
switch self {
case .dinersClub:
return [4, 10]
case .amex, .dinersClub:
indices = [4, 10]
case .unionPay:
if length == 19 {
indices = [5]
}
default:
return [4, 8, 12]
break
}
return indices
}
var securityCodeLength: Int {
if self == .amex {
return 4
@ -55,9 +75,21 @@ extension InputField {
}
}
var minLength: Int {
switch self {
case .visa: return 13
case .amex: return 15
case .dinersClub: return 14
default: return 16
}
}
var maxLength: Int {
switch self {
case .visa: return 19
case .amex: return 15
case .dinersClub: return 14
case .unionPay: return 19
default: return 16
}
}
@ -131,9 +163,8 @@ extension InputField {
override func appendRules(_ inputField: InputField) {
if let text = inputField.textField.text, text.count > 0 {
let rule = CharacterCountRule().copyWith {
$0.maxLength = inputField.cardType.maxLength
$0.compareType = .equals
let rule = CreditCardNumberRule().copyWith {
$0.cardType = inputField.cardType
$0.errorMessage = "Enter a valid credit card."
}
inputField.rules.append(.init(rule))
@ -205,8 +236,8 @@ extension InputField {
/// Private
internal func formatCreditCardNumber(_ cardType: CreditCardType, number: String) -> String {
let formattedInput = number.filter { $0.isNumber } // Remove any existing slashes
return String.format(formattedInput, indices: cardType.separatorIndices, with: " ")
let rawNumber = number.filter { $0.isNumber } // Remove any existing slashes
return String.format(rawNumber, indices: cardType.separatorIndices(rawNumber.count), with: " ")
}
internal func updateCardTypeIcon(_ inputField: InputField, rawNumber: String) {
@ -224,9 +255,8 @@ extension InputField {
guard rawNumber.count == cardType.maxLength else { return formatCreditCardNumber(cardType, number: number) }
let lastFourDigits = rawNumber.suffix(4)
let maskedSection = String(repeating: "", count: 12)
let formattedMaskSection = String.format(maskedSection, indices: cardType.separatorIndices, with: " ")
let formattedMaskSection = String.format(maskedSection, indices: cardType.separatorIndices(rawNumber.count), with: " ")
return formattedMaskSection + " " + lastFourDigits
}
}
}