refactored some of the credit card
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
5d9b744077
commit
819aa7a44e
@ -94,7 +94,11 @@ open class InputField: EntryFieldBase {
|
|||||||
|
|
||||||
/// Value for the textField
|
/// Value for the textField
|
||||||
open override var value: String? {
|
open override var value: String? {
|
||||||
textField.text
|
if fieldType == .creditCard {
|
||||||
|
return creditCardRawNumber
|
||||||
|
} else {
|
||||||
|
return textField.text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _showError: Bool = false
|
var _showError: Bool = false
|
||||||
@ -170,21 +174,29 @@ open class InputField: EntryFieldBase {
|
|||||||
.textPublisher
|
.textPublisher
|
||||||
.sink { [weak self] newText in
|
.sink { [weak self] newText in
|
||||||
print("textPublisher newText: \(newText)")
|
print("textPublisher newText: \(newText)")
|
||||||
self?.process(text: newText)
|
|
||||||
self?.validate()
|
|
||||||
self?.sendActions(for: .valueChanged)
|
self?.sendActions(for: .valueChanged)
|
||||||
}.store(in: &subscribers)
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
textField
|
textField
|
||||||
.publisher(for: .editingDidBegin)
|
.publisher(for: .editingDidBegin)
|
||||||
.sink { [weak self] _ in
|
.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)
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
textField
|
textField
|
||||||
.publisher(for: .editingDidEnd)
|
.publisher(for: .editingDidEnd)
|
||||||
.sink { [weak self] _ in
|
.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)
|
}.store(in: &subscribers)
|
||||||
|
|
||||||
stackView.addArrangedSubview(successLabel)
|
stackView.addArrangedSubview(successLabel)
|
||||||
@ -328,7 +340,7 @@ open class InputField: EntryFieldBase {
|
|||||||
rules.append(.init(rule))
|
rules.append(.init(rule))
|
||||||
case .securityCode:
|
case .securityCode:
|
||||||
minWidth = 88.0
|
minWidth = 88.0
|
||||||
|
isSecureTextEntry = true
|
||||||
}
|
}
|
||||||
|
|
||||||
//textField
|
//textField
|
||||||
@ -375,6 +387,16 @@ open class InputField: EntryFieldBase {
|
|||||||
super.updateRules()
|
super.updateRules()
|
||||||
|
|
||||||
switch fieldType {
|
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:
|
case .tel:
|
||||||
if let text = textField.text, text.count > 0 {
|
if let text = textField.text, text.count > 0 {
|
||||||
let rule = CharacterCountRule().copyWith {
|
let rule = CharacterCountRule().copyWith {
|
||||||
@ -473,6 +495,46 @@ open class InputField: EntryFieldBase {
|
|||||||
return formattedString
|
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
|
// MARK: - Telephone
|
||||||
//---------------------------------------------------
|
//---------------------------------------------------
|
||||||
private func formatUSNumber(_ number: String) -> String {
|
private func formatUSNumber(_ number: String) -> String {
|
||||||
@ -530,31 +592,55 @@ open class InputField: EntryFieldBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension InputField: UITextFieldDelegate {
|
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 {
|
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
|
||||||
// case text, number, inlineAction, password, creditCard, tel, date, securityCode
|
// case text, number, inlineAction, password, creditCard, tel, date, securityCode
|
||||||
|
|
||||||
switch fieldType {
|
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:
|
case .date:
|
||||||
// Allow only numbers and limit the length of text.
|
// Allow only numbers and limit the length of text.
|
||||||
guard let oldText = textField.text,
|
guard let oldText = textField.text,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user