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:
parent
f5380532ff
commit
2e46759857
@ -9,7 +9,20 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
extension InputField {
|
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 {
|
public enum CreditCardType: String, CaseIterable {
|
||||||
case generic
|
case generic
|
||||||
case visa
|
case visa
|
||||||
@ -38,15 +51,22 @@ extension InputField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var separatorIndices: [Int] {
|
func separatorIndices(_ length: Int) -> [Int] {
|
||||||
|
var indices: [Int] = [4, 8, 12]
|
||||||
switch self {
|
switch self {
|
||||||
case .dinersClub:
|
case .amex, .dinersClub:
|
||||||
return [4, 10]
|
indices = [4, 10]
|
||||||
|
case .unionPay:
|
||||||
|
if length == 19 {
|
||||||
|
indices = [5]
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return [4, 8, 12]
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return indices
|
||||||
}
|
}
|
||||||
|
|
||||||
var securityCodeLength: Int {
|
var securityCodeLength: Int {
|
||||||
if self == .amex {
|
if self == .amex {
|
||||||
return 4
|
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 {
|
var maxLength: Int {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .visa: return 19
|
||||||
|
case .amex: return 15
|
||||||
case .dinersClub: return 14
|
case .dinersClub: return 14
|
||||||
|
case .unionPay: return 19
|
||||||
default: return 16
|
default: return 16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,9 +163,8 @@ extension InputField {
|
|||||||
|
|
||||||
override func appendRules(_ inputField: InputField) {
|
override func appendRules(_ inputField: InputField) {
|
||||||
if let text = inputField.textField.text, text.count > 0 {
|
if let text = inputField.textField.text, text.count > 0 {
|
||||||
let rule = CharacterCountRule().copyWith {
|
let rule = CreditCardNumberRule().copyWith {
|
||||||
$0.maxLength = inputField.cardType.maxLength
|
$0.cardType = inputField.cardType
|
||||||
$0.compareType = .equals
|
|
||||||
$0.errorMessage = "Enter a valid credit card."
|
$0.errorMessage = "Enter a valid credit card."
|
||||||
}
|
}
|
||||||
inputField.rules.append(.init(rule))
|
inputField.rules.append(.init(rule))
|
||||||
@ -205,8 +236,8 @@ extension InputField {
|
|||||||
|
|
||||||
/// Private
|
/// Private
|
||||||
internal func formatCreditCardNumber(_ cardType: CreditCardType, number: String) -> String {
|
internal func formatCreditCardNumber(_ cardType: CreditCardType, number: String) -> String {
|
||||||
let formattedInput = number.filter { $0.isNumber } // Remove any existing slashes
|
let rawNumber = number.filter { $0.isNumber } // Remove any existing slashes
|
||||||
return String.format(formattedInput, indices: cardType.separatorIndices, with: " ")
|
return String.format(rawNumber, indices: cardType.separatorIndices(rawNumber.count), with: " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func updateCardTypeIcon(_ inputField: InputField, rawNumber: String) {
|
internal func updateCardTypeIcon(_ inputField: InputField, rawNumber: String) {
|
||||||
@ -224,9 +255,8 @@ extension InputField {
|
|||||||
guard rawNumber.count == cardType.maxLength else { return formatCreditCardNumber(cardType, number: number) }
|
guard rawNumber.count == cardType.maxLength else { return formatCreditCardNumber(cardType, number: number) }
|
||||||
let lastFourDigits = rawNumber.suffix(4)
|
let lastFourDigits = rawNumber.suffix(4)
|
||||||
let maskedSection = String(repeating: "•", count: 12)
|
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
|
return formattedMaskSection + " " + lastFourDigits
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user