refactored some of the credit card

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-05-08 17:00:41 -05:00
parent 5d9b744077
commit 819aa7a44e

View File

@ -94,7 +94,11 @@ open class InputField: EntryFieldBase {
/// Value for the textField
open override var value: String? {
textField.text
if fieldType == .creditCard {
return creditCardRawNumber
} else {
return textField.text
}
}
var _showError: Bool = false
@ -170,21 +174,29 @@ open class InputField: EntryFieldBase {
.textPublisher
.sink { [weak self] newText in
print("textPublisher newText: \(newText)")
self?.process(text: newText)
self?.validate()
self?.sendActions(for: .valueChanged)
}.store(in: &subscribers)
textField
.publisher(for: .editingDidBegin)
.sink { [weak self] _ in
self?.setNeedsUpdate()
guard let self else { return }
if self.fieldType == .creditCard {
self.isCreditCardMasked = false
self.textField.text = self.formatCreditCardNumber(self.creditCardRawNumber)
}
self.setNeedsUpdate()
}.store(in: &subscribers)
textField
.publisher(for: .editingDidEnd)
.sink { [weak self] _ in
self?.validate()
guard let self else { return }
if self.fieldType == .creditCard {
self.isCreditCardMasked = true
self.textField.text = self.maskCreditCardNumber(self.creditCardRawNumber)
}
self.validate()
}.store(in: &subscribers)
stackView.addArrangedSubview(successLabel)
@ -328,7 +340,7 @@ open class InputField: EntryFieldBase {
rules.append(.init(rule))
case .securityCode:
minWidth = 88.0
isSecureTextEntry = true
}
//textField
@ -375,6 +387,16 @@ open class InputField: EntryFieldBase {
super.updateRules()
switch fieldType {
case .creditCard:
if let text = textField.text, text.count > 0 {
let rule = CharacterCountRule().copyWith {
$0.maxLength = "XXXX XXXX XXXX XXXX".count
$0.compareType = .equals
$0.errorMessage = "Enter a valid credit card."
}
rules.append(.init(rule))
}
case .tel:
if let text = textField.text, text.count > 0 {
let rule = CharacterCountRule().copyWith {
@ -473,6 +495,46 @@ open class InputField: EntryFieldBase {
return formattedString
}
//---------------------------------------------------
// MARK: - Credit Card
//---------------------------------------------------
private var isCreditCardMasked: Bool = false
private var creditCardRawNumber: String = ""
private var creditCardMaxLength = 16
private func formatCreditCardNumber(_ number: String) -> String {
// Format the number in the style XXXX XXXX XXXX XXXX
var formattedNumber = ""
for (index, char) in number.enumerated() {
if index != 0 && index % 4 == 0 {
formattedNumber.append(" ")
}
formattedNumber.append(char)
}
return formattedNumber
}
private func updateCardTypeIcon(rawNumber: String) {
// let firstFourDigits = String(rawNumber.prefix(4))
// if let icon = cardTypeIcons[firstFourDigits] {
// cardTypeIconView.image = icon
// } else {
// cardTypeIconView.image = nil
// }
}
private func maskCreditCardNumber(_ number: String) -> String {
// Mask the first 12 characters if the length is 16
let rawNumber = number.filter { $0.isNumber }
guard rawNumber.count == creditCardMaxLength else { return number }
let lastFourDigits = rawNumber.suffix(4)
let maskedSection = String(repeating: "", count: 12)
let formattedMaskSection = formatCreditCardNumber(maskedSection)
return formattedMaskSection + " " + lastFourDigits
}
//---------------------------------------------------
// MARK: - Telephone
//---------------------------------------------------
private func formatUSNumber(_ number: String) -> String {
@ -530,31 +592,55 @@ open class InputField: EntryFieldBase {
}
extension InputField: UITextFieldDelegate {
public func process(text changedText: String) {
var newText: String = changedText
switch fieldType {
case .date:
guard newText.count <= dateFormat.maxLength else { return }
let numericText = newText.compactMap { $0.isNumber ? $0 : nil }
var formattedText = ""
for (index, char) in numericText.enumerated() {
if (index == 2 || (index == 4 && (dateFormat != .mmyy))) && index < dateFormat.maxLength {
formattedText += "/"
}
formattedText.append(char)
}
newText = formattedText
default: break
}
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// case text, number, inlineAction, password, creditCard, tel, date, securityCode
switch fieldType {
case .creditCard:
let allowedCharacters = CharacterSet.decimalDigits
if string.rangeOfCharacter(from: allowedCharacters.inverted) != nil && !string.isEmpty {
return false
}
// Get the current text
let currentText = textField.text ?? ""
// Calculate the new text
let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
// Remove any existing formatting
let rawNumber = newText.filter { $0.isNumber }
if rawNumber.count > creditCardMaxLength {
return false
}
// Format the number with spaces
let formattedNumber = formatCreditCardNumber(rawNumber)
// Update the icon based on the first four digits
updateCardTypeIcon(rawNumber: rawNumber)
// Set the formatted text
textField.text = formattedNumber
// Calculate the new cursor position
if let newPosition = getTelCursorPosition(textField: textField,
range: range,
replacementString: string,
rawNumber: rawNumber,
formattedNumber: formattedNumber) {
textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition)
}
// if all passes, then set the number1
creditCardRawNumber = rawNumber
// Prevent the default behavior
return false
case .date:
// Allow only numbers and limit the length of text.
guard let oldText = textField.text,