@jimrising/easymerchantsdk-react-native 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/caches/deviceStreaming.xml +340 -0
- package/.idea/em-MobileCheckoutSDK-ReactNative.iml +9 -0
- package/.idea/misc.xml +5 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/README.md +230 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/results.bin +1 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
- package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/41cd2635778c1bb5c18af2c46eb9196e/results.bin +1 -0
- package/android/build/.transforms/41cd2635778c1bb5c18af2c46eb9196e/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/results.bin +1 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
- package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/7eb7ceaa43c9e8323ac65b4f785987b6/results.bin +1 -0
- package/android/build/.transforms/7eb7ceaa43c9e8323ac65b4f785987b6/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/results.bin +1 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
- package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/f1a160720415bc76d8d6c6734c5acf3e/results.bin +1 -0
- package/android/build/.transforms/f1a160720415bc76d8d6c6734c5acf3e/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/generated/source/buildConfig/debug/com/reactlibrary/BuildConfig.java +10 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +7 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/BuildConfig.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +7 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +7 -0
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/BuildConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +17 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId2 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId1 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId0 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build.gradle +55 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +72 -0
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkPackage.java +28 -0
- package/index.js +5 -0
- package/ios/Bundle/EasyPayBundle.swift +22 -0
- package/ios/Classes/EasyMerchantSdk.h +4 -0
- package/ios/Classes/EasyMerchantSdk.m +43 -0
- package/ios/Classes/EasyMerchantSdk.swift +124 -0
- package/ios/Classes/EasyPayViewController.swift +90 -0
- package/ios/CustomComponents/CheckboxButton.swift +20 -0
- package/ios/CustomComponents/FilledButton.swift +17 -0
- package/ios/CustomComponents/OutlineButton.swift +26 -0
- package/ios/CustomComponents/TextFieldStackView.swift +96 -0
- package/ios/EnvironmentConfig.swift +63 -0
- package/ios/Example/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- package/ios/Example/Assets.xcassets/Contents.json +6 -0
- package/ios/Example/Base.lproj/LaunchScreen.storyboard +25 -0
- package/ios/Example/Base.lproj/Main.storyboard +65 -0
- package/ios/Example/SceneDelegate.swift +52 -0
- package/ios/Example/ViewController.swift +84 -0
- package/ios/Extensions/UIColor.swift +22 -0
- package/ios/Extensions/UIFont.swift +80 -0
- package/ios/Extensions/UIViewController+Extension.swift +42 -0
- package/ios/Models/AdditionalInfo.swift +16 -0
- package/ios/Models/BankAccountModel.swift +23 -0
- package/ios/Models/BillingInfo.swift +16 -0
- package/ios/Models/CardModel.swift +19 -0
- package/ios/Models/Country.swift +19 -0
- package/ios/Models/PaymentInfo.swift +46 -0
- package/ios/Models/Request.swift +245 -0
- package/ios/Models/Result.swift +69 -0
- package/ios/Pods/UserDefaults/UserStoreSingleton.swift +200 -0
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +1073 -0
- package/ios/Pods/ViewControllers/BaseVC.swift +117 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +616 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CityListTVC.swift +19 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CountryListTVC.swift +19 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/StateListTVC.swift +19 -0
- package/ios/Pods/ViewControllers/CountryListVC.swift +367 -0
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +192 -0
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +1009 -0
- package/ios/Pods/ViewControllers/PaymentDoneVC.swift +94 -0
- package/ios/Pods/ViewControllers/PaymentErrorVC.swift +43 -0
- package/ios/Pods/ViewControllers/PaymentInformation/AccountTypeTVC.swift +19 -0
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +4269 -0
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInformationCVC.swift +20 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.swift +37 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.xib +163 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.swift +40 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.xib +184 -0
- package/ios/Pods/ViewControllers/TermAndConditionsVC.swift +21 -0
- package/ios/Resources/Assets.xcassets/Card/Amex.imageset/206682_american_express_method_card_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/Amex.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/Contents.json +6 -0
- package/ios/Resources/Assets.xcassets/Card/DinersClub.imageset/472318_card_club_diners_dinner_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/DinersClub.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/Discover.imageset/206686_network_payment_discover_card_method_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/Discover.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/JCB.imageset/358102_card_jcb_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/JCB.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/MasterCard.imageset/206680_master_method_card_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/MasterCard.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/UnionPay.imageset/1468976_card_payment_unionpay_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/UnionPay.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/Visa.imageset/206684_visa_method_card_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/Visa.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/maestro.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/maestro.imageset/maestro.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/paypal.imageset/206675_paypal_method_payment_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/paypal.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/rupay.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/rupay.imageset/rupay.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/unknown_card.imageset/4635000_card_credit_digital_money_icon.svg +1 -0
- package/ios/Resources/Assets.xcassets/Card/unknown_card.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/worldpay.imageset/Contents.json +12 -0
- package/ios/Resources/Assets.xcassets/Card/worldpay.imageset/worldpay.svg +1 -0
- package/ios/Resources/Assets.xcassets/Contents.json +6 -0
- package/ios/Resources/Assets.xcassets/Ellipsis.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-30.png +0 -0
- package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-60.png +0 -0
- package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-90.png +0 -0
- package/ios/Resources/Assets.xcassets/Rotate.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw-2.png +0 -0
- package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw-3.png +0 -0
- package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw.png +0 -0
- package/ios/Resources/Assets.xcassets/amexCvc.imageset/Contents.json +22 -0
- package/ios/Resources/Assets.xcassets/amexCvc.imageset/Group-1.png +0 -0
- package/ios/Resources/Assets.xcassets/amexCvc.imageset/Group.png +0 -0
- package/ios/Resources/Assets.xcassets/check.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/check.imageset/check-circle-4.png +0 -0
- package/ios/Resources/Assets.xcassets/check.imageset/check-circle-5.png +0 -0
- package/ios/Resources/Assets.xcassets/check.imageset/check-circle-6.png +0 -0
- package/ios/Resources/Assets.xcassets/chip.imageset/Contents.json +21 -0
- package/ios/Resources/Assets.xcassets/chip.imageset/chip.png +0 -0
- package/ios/Resources/Assets.xcassets/loaderImage.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle-2.png +0 -0
- package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle-3.png +0 -0
- package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon 1.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon 2.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon 1.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon 2.png +0 -0
- package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon.png +0 -0
- package/ios/Resources/Assets.xcassets/wallet.imageset/Contents.json +23 -0
- package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-24(@1/303/227).png +0 -0
- package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-48(@2/303/227).png +0 -0
- package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-72(@3/303/227).png +0 -0
- package/ios/Resources/Colors.xcassets/00000008.colorset/Contents.json +20 -0
- package/ios/Resources/Colors.xcassets/00000016.colorset/Contents.json +20 -0
- package/ios/Resources/Colors.xcassets/00000038.colorset/Contents.json +20 -0
- package/ios/Resources/Colors.xcassets/00000060.colorset/Contents.json +20 -0
- package/ios/Resources/Colors.xcassets/1757D9.colorset/Contents.json +20 -0
- package/ios/Resources/Colors.xcassets/Contents.json +6 -0
- package/ios/Resources/Colors.xcassets/E93939.colorset/Contents.json +20 -0
- package/ios/Resources/PrivacyInfo.xcprivacy +10 -0
- package/ios/ThirdParty/Keyboad Handling/KeyboardObserver.swift +74 -0
- package/ios/easymerchantsdk.podspec +80 -0
- package/ios/easymerchantsdk.storyboard +5885 -0
- package/package.json +27 -0
- package/src/index.js +44 -0
|
@@ -0,0 +1,1009 @@
|
|
|
1
|
+
//
|
|
2
|
+
// OTPVerificationVC.swift
|
|
3
|
+
// EasyPay
|
|
4
|
+
//
|
|
5
|
+
// Created by Mony's Mac on 14/08/24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
|
|
10
|
+
class OTPVerificationVC: BaseVC {
|
|
11
|
+
|
|
12
|
+
@IBOutlet weak var viewTextOTP1: UIView!
|
|
13
|
+
@IBOutlet weak var txtFieldOTPText1: UITextField!
|
|
14
|
+
@IBOutlet weak var viewTextOTP2: UIView!
|
|
15
|
+
@IBOutlet weak var txtFieldOTPText2: UITextField!
|
|
16
|
+
@IBOutlet weak var viewTextOTP3: UIView!
|
|
17
|
+
@IBOutlet weak var txtFieldOTPText3: UITextField!
|
|
18
|
+
@IBOutlet weak var viewTextOTP4: UIView!
|
|
19
|
+
@IBOutlet weak var txtFieldOTPText4: UITextField!
|
|
20
|
+
@IBOutlet weak var viewTextOTP5: UIView!
|
|
21
|
+
@IBOutlet weak var txtFieldOTPText5: UITextField!
|
|
22
|
+
@IBOutlet weak var viewTextOTP6: UIView!
|
|
23
|
+
@IBOutlet weak var txtFieldOTPText6: UITextField!
|
|
24
|
+
@IBOutlet weak var imgEsclamationMark: UIImageView!
|
|
25
|
+
@IBOutlet weak var lblOtpTimer: UILabel!
|
|
26
|
+
@IBOutlet weak var lblUntillResendOtp: UILabel!
|
|
27
|
+
@IBOutlet weak var btnResendOTP: UIButton!
|
|
28
|
+
|
|
29
|
+
var cardNumber: String?
|
|
30
|
+
var expiryDate: String?
|
|
31
|
+
var cvv: String?
|
|
32
|
+
var nameOnCard: String?
|
|
33
|
+
var billingInfoData: [String: Any]?
|
|
34
|
+
|
|
35
|
+
var email: String?
|
|
36
|
+
|
|
37
|
+
var selectedPaymentMethod: String?
|
|
38
|
+
|
|
39
|
+
//Banking Params
|
|
40
|
+
var accountName: String?
|
|
41
|
+
var routingNumber: String?
|
|
42
|
+
var accountType: String?
|
|
43
|
+
var accountNumber: String?
|
|
44
|
+
|
|
45
|
+
var easyPayDelegate: EasyPayViewControllerDelegate?
|
|
46
|
+
|
|
47
|
+
var easyPayVC: EasyPayViewController?
|
|
48
|
+
|
|
49
|
+
var isSavedForFuture: Bool = false
|
|
50
|
+
|
|
51
|
+
private var timeRemaining = 180 // 3 minutes
|
|
52
|
+
private var timer: Timer?
|
|
53
|
+
|
|
54
|
+
override func viewDidLoad() {
|
|
55
|
+
super.viewDidLoad()
|
|
56
|
+
|
|
57
|
+
// Add tap gesture recognizer to dismiss the keyboard
|
|
58
|
+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
|
|
59
|
+
view.addGestureRecognizer(tapGesture)
|
|
60
|
+
|
|
61
|
+
setupTextFields()
|
|
62
|
+
|
|
63
|
+
btnResendOTP.isHidden = true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
67
|
+
startTimer()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Method to dismiss the keyboard
|
|
71
|
+
@objc func dismissKeyboard() {
|
|
72
|
+
view.endEditing(true)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private func startTimer() {
|
|
76
|
+
timeRemaining = 180 // 3 minutes
|
|
77
|
+
lblOtpTimer.text = formatTime(timeRemaining)
|
|
78
|
+
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private func stopTimer() {
|
|
82
|
+
timer?.invalidate()
|
|
83
|
+
timer = nil
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@objc private func updateTimer() {
|
|
87
|
+
if timeRemaining > 0 {
|
|
88
|
+
timeRemaining -= 1
|
|
89
|
+
lblOtpTimer.text = formatTime(timeRemaining)
|
|
90
|
+
} else {
|
|
91
|
+
stopTimer()
|
|
92
|
+
btnResendOTP.isHidden = false
|
|
93
|
+
imgEsclamationMark.isHidden = true
|
|
94
|
+
lblOtpTimer.isHidden = true
|
|
95
|
+
lblUntillResendOtp.isHidden = true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private func formatTime(_ seconds: Int) -> String {
|
|
100
|
+
let minutes = seconds / 60
|
|
101
|
+
let seconds = seconds % 60
|
|
102
|
+
return String(format: "%02d:%02d", minutes, seconds)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private func setupTextFields() {
|
|
106
|
+
let textFields = [txtFieldOTPText1, txtFieldOTPText2, txtFieldOTPText3, txtFieldOTPText4, txtFieldOTPText5, txtFieldOTPText6]
|
|
107
|
+
|
|
108
|
+
for textField in textFields {
|
|
109
|
+
textField?.delegate = self
|
|
110
|
+
textField?.textContentType = .oneTimeCode
|
|
111
|
+
textField?.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//MARK: - OTP Verification Api
|
|
116
|
+
func otpVerificationApi() {
|
|
117
|
+
showLoadingIndicator()
|
|
118
|
+
|
|
119
|
+
// var components = URLComponents()
|
|
120
|
+
// components.scheme = "https"
|
|
121
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
122
|
+
// components.path = "/api/v1/customer/verify_otp"
|
|
123
|
+
//
|
|
124
|
+
// guard let serviceURL = components.url else {
|
|
125
|
+
// print("Invalid URL")
|
|
126
|
+
// hideLoadingIndicator()
|
|
127
|
+
// return
|
|
128
|
+
// }
|
|
129
|
+
|
|
130
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
131
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.verifyOtp.path()
|
|
132
|
+
|
|
133
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
134
|
+
print("Invalid URL")
|
|
135
|
+
hideLoadingIndicator()
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var request = URLRequest(url: serviceURL)
|
|
140
|
+
request.httpMethod = "POST"
|
|
141
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
142
|
+
|
|
143
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
144
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
145
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
146
|
+
|
|
147
|
+
let params: [String: Any] = [
|
|
148
|
+
"card_search_value": email ?? "",
|
|
149
|
+
"card_search_key": "email",
|
|
150
|
+
"otp": getCombinedOTP()
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
do {
|
|
154
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
155
|
+
request.httpBody = jsonData
|
|
156
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
157
|
+
print("JSON Payload: \(jsonString)")
|
|
158
|
+
}
|
|
159
|
+
} catch let error {
|
|
160
|
+
print("Error creating JSON data: \(error)")
|
|
161
|
+
hideLoadingIndicator()
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let session = URLSession.shared
|
|
166
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
167
|
+
|
|
168
|
+
DispatchQueue.main.async {
|
|
169
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if let error = error {
|
|
173
|
+
print("Error: \(error.localizedDescription)")
|
|
174
|
+
return
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
178
|
+
print("Invalid response")
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
183
|
+
if let data = serviceData {
|
|
184
|
+
do {
|
|
185
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
186
|
+
print("Response Data: \(responseObject)")
|
|
187
|
+
if self.selectedPaymentMethod == "Card" {
|
|
188
|
+
if let dataSection = responseObject["data"] as? [String: Any],
|
|
189
|
+
let innerData = dataSection["data"] as? [String: Any],
|
|
190
|
+
let customerId = innerData["customer_id"] as? String {
|
|
191
|
+
print("Extracted customer_id: \(customerId)")
|
|
192
|
+
if self.billingInfoData == nil {
|
|
193
|
+
self.paymentIntentWithSavedCardApi(customerId: customerId)
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
self.paymentIntentApi(customerId: customerId)
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
print("customer_id not found in nested data. Falling back to nil.")
|
|
200
|
+
self.paymentIntentApi(customerId: nil)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else if self.selectedPaymentMethod == "Bank" {
|
|
204
|
+
|
|
205
|
+
if let dataSection = responseObject["data"] as? [String: Any],
|
|
206
|
+
let innerData = dataSection["data"] as? [String: Any],
|
|
207
|
+
let customerId = innerData["customer_id"] as? String {
|
|
208
|
+
print("Extracted customer_id: \(customerId)")
|
|
209
|
+
if self.billingInfoData == nil {
|
|
210
|
+
self.accountChargeWithSavedAccountApi(customerId: customerId)
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
self.accountChargeApi(customerId: customerId)
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
print("customer_id not found in nested data. Falling back to nil.")
|
|
217
|
+
if self.billingInfoData == nil {
|
|
218
|
+
self.accountChargeWithSavedAccountApi(customerId: nil)
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
self.accountChargeApi(customerId: nil)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
print("Invalid JSON format")
|
|
228
|
+
}
|
|
229
|
+
} catch let jsonError {
|
|
230
|
+
print("Error parsing JSON: \(jsonError)")
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
print("No data received")
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
print("HTTP Status Code: \(httpResponse.statusCode)")
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
task.resume()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
//MARK: - Send OTP Email Verification Api
|
|
243
|
+
func emailVerificationApi() {
|
|
244
|
+
showLoadingIndicator()
|
|
245
|
+
// var components = URLComponents()
|
|
246
|
+
// components.scheme = "https"
|
|
247
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
248
|
+
// components.path = "/api/v1/customer/send_otp"
|
|
249
|
+
//
|
|
250
|
+
// guard let serviceURL = components.url else {
|
|
251
|
+
// print("Invalid URL")
|
|
252
|
+
// hideLoadingIndicator()
|
|
253
|
+
// return
|
|
254
|
+
// }
|
|
255
|
+
|
|
256
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
257
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.emailVerification.path()
|
|
258
|
+
|
|
259
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
260
|
+
print("Invalid URL")
|
|
261
|
+
hideLoadingIndicator()
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
var request = URLRequest(url: serviceURL)
|
|
266
|
+
request.httpMethod = "POST"
|
|
267
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
268
|
+
|
|
269
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
270
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
271
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
272
|
+
|
|
273
|
+
let params: [String: Any] = [
|
|
274
|
+
"card_search_value": email ?? "",
|
|
275
|
+
"card_search_key": "email"
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
do {
|
|
279
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
280
|
+
request.httpBody = jsonData
|
|
281
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
282
|
+
print("JSON Payload: \(jsonString)")
|
|
283
|
+
}
|
|
284
|
+
} catch let error {
|
|
285
|
+
print("Error creating JSON data: \(error)")
|
|
286
|
+
hideLoadingIndicator()
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let session = URLSession.shared
|
|
291
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
292
|
+
|
|
293
|
+
DispatchQueue.main.async {
|
|
294
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if let error = error {
|
|
298
|
+
print("Error: \(error.localizedDescription)")
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
303
|
+
print("Invalid response")
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
308
|
+
if let data = serviceData {
|
|
309
|
+
do {
|
|
310
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
311
|
+
print("Response Data: \(responseObject)")
|
|
312
|
+
|
|
313
|
+
} else {
|
|
314
|
+
print("Invalid JSON format")
|
|
315
|
+
}
|
|
316
|
+
} catch let jsonError {
|
|
317
|
+
print("Error parsing JSON: \(jsonError)")
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
print("No data received")
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
print("HTTP Status Code: \(httpResponse.statusCode)")
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
task.resume()
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
//MARK: - Card Charge Api
|
|
330
|
+
func paymentIntentApi(customerId: String?) {
|
|
331
|
+
showLoadingIndicator()
|
|
332
|
+
|
|
333
|
+
// var components = URLComponents()
|
|
334
|
+
// components.scheme = "https"
|
|
335
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
336
|
+
// components.path = "/api/v1/charges"
|
|
337
|
+
//
|
|
338
|
+
// guard let serviceURL = components.url else {
|
|
339
|
+
// print("Invalid URL")
|
|
340
|
+
// hideLoadingIndicator()
|
|
341
|
+
// return
|
|
342
|
+
// }
|
|
343
|
+
|
|
344
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
345
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
346
|
+
|
|
347
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
348
|
+
print("Invalid URL")
|
|
349
|
+
hideLoadingIndicator()
|
|
350
|
+
return
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
var request = URLRequest(url: serviceURL)
|
|
354
|
+
request.httpMethod = "POST"
|
|
355
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
356
|
+
|
|
357
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
358
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
359
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
360
|
+
|
|
361
|
+
guard let billingInfoData = billingInfoData else {
|
|
362
|
+
print("Billing info data is nil")
|
|
363
|
+
return
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
let additionalInfoFromBilling = billingInfoData["additional_info"] as? [String: Any] ?? [:]
|
|
367
|
+
|
|
368
|
+
let additionalInfo: [String: Any] = [
|
|
369
|
+
"name": additionalInfoFromBilling["name"] as? String ?? "",
|
|
370
|
+
"email": additionalInfoFromBilling["email"] as? String ?? "",
|
|
371
|
+
"phone_number": additionalInfoFromBilling["phone_number"] as? String ?? "",
|
|
372
|
+
"description": additionalInfoFromBilling["description"] as? String ?? ""
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
let billingInfo: [String: Any] = [
|
|
376
|
+
"address": billingInfoData["address"] as? String ?? "",
|
|
377
|
+
"country": billingInfoData["country"] as? String ?? "",
|
|
378
|
+
"state": billingInfoData["state"] as? String ?? "",
|
|
379
|
+
"city": billingInfoData["city"] as? String ?? "",
|
|
380
|
+
"postal_code": billingInfoData["postal_code"] as? String ?? ""
|
|
381
|
+
]
|
|
382
|
+
|
|
383
|
+
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
384
|
+
|
|
385
|
+
var params: [String: Any] = [
|
|
386
|
+
"name": additionalInfoFromBilling["name"] as? String ?? "",
|
|
387
|
+
"card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
388
|
+
"cardholder_name": nameOnCard ?? "",
|
|
389
|
+
"exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
|
|
390
|
+
"exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
|
|
391
|
+
"cvc": cvv ?? "",
|
|
392
|
+
"description": additionalInfoFromBilling["description"] as? String ?? "",
|
|
393
|
+
"currency": "usd",
|
|
394
|
+
"billing_info": billingInfo,
|
|
395
|
+
"additional_info": additionalInfo,
|
|
396
|
+
"payment_method": selectedPaymentMethod ?? "",
|
|
397
|
+
"save_card": 1,
|
|
398
|
+
"is_default": "1"
|
|
399
|
+
]
|
|
400
|
+
|
|
401
|
+
if let customerId = customerId {
|
|
402
|
+
params["customer"] = customerId
|
|
403
|
+
params["customer_id"] = customerId
|
|
404
|
+
} else {
|
|
405
|
+
params["username"] = emailPrefix
|
|
406
|
+
params["email"] = email ?? ""
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
print(params)
|
|
410
|
+
|
|
411
|
+
do {
|
|
412
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
413
|
+
request.httpBody = jsonData
|
|
414
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
415
|
+
print("JSON Payload: \(jsonString)")
|
|
416
|
+
}
|
|
417
|
+
} catch let error {
|
|
418
|
+
print("Error creating JSON data: \(error)")
|
|
419
|
+
hideLoadingIndicator()
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let session = URLSession.shared
|
|
424
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
425
|
+
|
|
426
|
+
DispatchQueue.main.async {
|
|
427
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if let error = error {
|
|
431
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
436
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
441
|
+
if let data = serviceData {
|
|
442
|
+
do {
|
|
443
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
444
|
+
print("Response Data: \(responseObject)")
|
|
445
|
+
|
|
446
|
+
// Check if status is 0 and handle the error
|
|
447
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
448
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
449
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
450
|
+
} else {
|
|
451
|
+
DispatchQueue.main.async {
|
|
452
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
453
|
+
paymentDoneVC.chargeData = responseObject
|
|
454
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
455
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
456
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
461
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
462
|
+
}
|
|
463
|
+
} catch let jsonError {
|
|
464
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
468
|
+
}
|
|
469
|
+
} else {
|
|
470
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
task.resume()
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
//MARK: - Card Charge Api If billing info is nil and saved card
|
|
477
|
+
func paymentIntentWithSavedCardApi(customerId: String?) {
|
|
478
|
+
showLoadingIndicator()
|
|
479
|
+
|
|
480
|
+
// var components = URLComponents()
|
|
481
|
+
// components.scheme = "https"
|
|
482
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
483
|
+
// components.path = "/api/v1/charges"
|
|
484
|
+
//
|
|
485
|
+
// guard let serviceURL = components.url else {
|
|
486
|
+
// print("Invalid URL")
|
|
487
|
+
// hideLoadingIndicator()
|
|
488
|
+
// return
|
|
489
|
+
// }
|
|
490
|
+
|
|
491
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
492
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
493
|
+
|
|
494
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
495
|
+
print("Invalid URL")
|
|
496
|
+
hideLoadingIndicator()
|
|
497
|
+
return
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
var request = URLRequest(url: serviceURL)
|
|
501
|
+
request.httpMethod = "POST"
|
|
502
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
503
|
+
|
|
504
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
505
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
506
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
507
|
+
|
|
508
|
+
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
509
|
+
|
|
510
|
+
var params: [String: Any] = [
|
|
511
|
+
"name": emailPrefix,
|
|
512
|
+
"card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
513
|
+
"cardholder_name": nameOnCard ?? "",
|
|
514
|
+
"exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
|
|
515
|
+
"exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
|
|
516
|
+
"cvc": cvv ?? "",
|
|
517
|
+
"description": "description",
|
|
518
|
+
"currency": "usd",
|
|
519
|
+
"payment_method": selectedPaymentMethod ?? "",
|
|
520
|
+
"save_card": 1,
|
|
521
|
+
"is_default": "1"
|
|
522
|
+
]
|
|
523
|
+
|
|
524
|
+
if let customerId = customerId {
|
|
525
|
+
params["customer"] = customerId
|
|
526
|
+
params["customer_id"] = customerId
|
|
527
|
+
} else {
|
|
528
|
+
params["username"] = emailPrefix
|
|
529
|
+
params["email"] = email ?? ""
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
print(params)
|
|
533
|
+
|
|
534
|
+
do {
|
|
535
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
536
|
+
request.httpBody = jsonData
|
|
537
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
538
|
+
print("JSON Payload: \(jsonString)")
|
|
539
|
+
}
|
|
540
|
+
} catch let error {
|
|
541
|
+
print("Error creating JSON data: \(error)")
|
|
542
|
+
hideLoadingIndicator()
|
|
543
|
+
return
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
let session = URLSession.shared
|
|
547
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
548
|
+
|
|
549
|
+
DispatchQueue.main.async {
|
|
550
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if let error = error {
|
|
554
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
559
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
560
|
+
return
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
564
|
+
if let data = serviceData {
|
|
565
|
+
do {
|
|
566
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
567
|
+
print("Response Data: \(responseObject)")
|
|
568
|
+
|
|
569
|
+
// Check if status is 0 and handle the error
|
|
570
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
571
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
572
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
573
|
+
} else {
|
|
574
|
+
DispatchQueue.main.async {
|
|
575
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
576
|
+
paymentDoneVC.chargeData = responseObject
|
|
577
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
578
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
579
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
} else {
|
|
584
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
585
|
+
}
|
|
586
|
+
} catch let jsonError {
|
|
587
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
588
|
+
}
|
|
589
|
+
} else {
|
|
590
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
task.resume()
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
func presentPaymentErrorVC(errorMessage: String) {
|
|
600
|
+
DispatchQueue.main.async {
|
|
601
|
+
if let paymentErrorVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentErrorVC") as? PaymentErrorVC {
|
|
602
|
+
paymentErrorVC.errorMessage = errorMessage
|
|
603
|
+
paymentErrorVC.easyPayDelegate = self.easyPayDelegate // Pass the reference here
|
|
604
|
+
self.navigationController?.pushViewController(paymentErrorVC, animated: true)
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
//MARK: - Account Charge Api
|
|
610
|
+
func accountChargeApi(customerId: String?) {
|
|
611
|
+
showLoadingIndicator()
|
|
612
|
+
|
|
613
|
+
// var components = URLComponents()
|
|
614
|
+
// components.scheme = "https"
|
|
615
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
616
|
+
// components.path = "/api/v1/ach/charge"
|
|
617
|
+
//
|
|
618
|
+
// guard let serviceURL = components.url else {
|
|
619
|
+
// print("Invalid URL")
|
|
620
|
+
// hideLoadingIndicator()
|
|
621
|
+
// return
|
|
622
|
+
// }
|
|
623
|
+
|
|
624
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
625
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
626
|
+
|
|
627
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
628
|
+
print("Invalid URL")
|
|
629
|
+
hideLoadingIndicator()
|
|
630
|
+
return
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
var request = URLRequest(url: serviceURL)
|
|
634
|
+
request.httpMethod = "POST"
|
|
635
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
636
|
+
|
|
637
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
638
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
639
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
640
|
+
|
|
641
|
+
guard let billingInfoData = billingInfoData else {
|
|
642
|
+
print("Billing info data is nil")
|
|
643
|
+
return
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
let additionalInfoFromBilling = billingInfoData["additional_info"] as? [String: Any] ?? [:]
|
|
647
|
+
|
|
648
|
+
let additionalInfo: [String: Any] = [
|
|
649
|
+
"name": additionalInfoFromBilling["name"] as? String ?? "",
|
|
650
|
+
"email": additionalInfoFromBilling["email"] as? String ?? "",
|
|
651
|
+
"phone_number": additionalInfoFromBilling["phone_number"] as? String ?? "",
|
|
652
|
+
"description": additionalInfoFromBilling["description"] as? String ?? ""
|
|
653
|
+
]
|
|
654
|
+
|
|
655
|
+
let billingInfo: [String: Any] = [
|
|
656
|
+
"address": billingInfoData["address"] as? String ?? "",
|
|
657
|
+
"country": billingInfoData["country"] as? String ?? "",
|
|
658
|
+
"state": billingInfoData["state"] as? String ?? "",
|
|
659
|
+
"city": billingInfoData["city"] as? String ?? "",
|
|
660
|
+
"postal_code": billingInfoData["postal_code"] as? String ?? ""
|
|
661
|
+
]
|
|
662
|
+
|
|
663
|
+
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
664
|
+
|
|
665
|
+
var params: [String: Any] = [
|
|
666
|
+
"name": additionalInfoFromBilling["name"] as? String ?? "",
|
|
667
|
+
"email": email ?? "",
|
|
668
|
+
"description": additionalInfoFromBilling["description"] as? String ?? "",
|
|
669
|
+
"currency": "usd",
|
|
670
|
+
"billing_info": billingInfo,
|
|
671
|
+
"additional_info": additionalInfo,
|
|
672
|
+
"account_type": accountType?.lowercased() ?? "",
|
|
673
|
+
"routing_number": routingNumber ?? "",
|
|
674
|
+
"account_number": accountNumber ?? "",
|
|
675
|
+
"payment_mode": "auth_and_capture",
|
|
676
|
+
"payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
|
|
677
|
+
"levelIndicator": 1,
|
|
678
|
+
"save_account": 1,
|
|
679
|
+
"payment_method": "ach"
|
|
680
|
+
]
|
|
681
|
+
|
|
682
|
+
if let customerId = customerId {
|
|
683
|
+
params["customer"] = customerId
|
|
684
|
+
} else {
|
|
685
|
+
params["username"] = emailPrefix
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
print(params)
|
|
689
|
+
|
|
690
|
+
do {
|
|
691
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
692
|
+
request.httpBody = jsonData
|
|
693
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
694
|
+
print("JSON Payload: \(jsonString)")
|
|
695
|
+
}
|
|
696
|
+
} catch let error {
|
|
697
|
+
print("Error creating JSON data: \(error)")
|
|
698
|
+
hideLoadingIndicator()
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
let session = URLSession.shared
|
|
703
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
704
|
+
|
|
705
|
+
DispatchQueue.main.async {
|
|
706
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if let error = error {
|
|
710
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
711
|
+
return
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
715
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
716
|
+
return
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
720
|
+
if let data = serviceData {
|
|
721
|
+
do {
|
|
722
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
723
|
+
print("Response Data: \(responseObject)")
|
|
724
|
+
|
|
725
|
+
// Check if status is 0 and handle the error
|
|
726
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
727
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
728
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
729
|
+
} else {
|
|
730
|
+
DispatchQueue.main.async {
|
|
731
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
732
|
+
paymentDoneVC.chargeData = responseObject
|
|
733
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
734
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
735
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
} else {
|
|
740
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
741
|
+
}
|
|
742
|
+
} catch let jsonError {
|
|
743
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
744
|
+
}
|
|
745
|
+
} else {
|
|
746
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
task.resume()
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
//MARK: - Account Charge Api if billing info is nil and saved account
|
|
756
|
+
func accountChargeWithSavedAccountApi(customerId: String?) {
|
|
757
|
+
showLoadingIndicator()
|
|
758
|
+
|
|
759
|
+
// var components = URLComponents()
|
|
760
|
+
// components.scheme = "https"
|
|
761
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
762
|
+
// components.path = "/api/v1/ach/charge"
|
|
763
|
+
//
|
|
764
|
+
// guard let serviceURL = components.url else {
|
|
765
|
+
// print("Invalid URL")
|
|
766
|
+
// hideLoadingIndicator()
|
|
767
|
+
// return
|
|
768
|
+
// }
|
|
769
|
+
|
|
770
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
771
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
772
|
+
|
|
773
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
774
|
+
print("Invalid URL")
|
|
775
|
+
hideLoadingIndicator()
|
|
776
|
+
return
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
var request = URLRequest(url: serviceURL)
|
|
780
|
+
request.httpMethod = "POST"
|
|
781
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
782
|
+
|
|
783
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
784
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
785
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
786
|
+
|
|
787
|
+
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
788
|
+
|
|
789
|
+
var params: [String: Any] = [
|
|
790
|
+
"name": emailPrefix,
|
|
791
|
+
"email": email ?? "",
|
|
792
|
+
"description": "Test Description",
|
|
793
|
+
"currency": "usd",
|
|
794
|
+
"account_type": accountType?.lowercased() ?? "",
|
|
795
|
+
"routing_number": routingNumber ?? "",
|
|
796
|
+
"account_number": accountNumber ?? "",
|
|
797
|
+
"payment_mode": "auth_and_capture",
|
|
798
|
+
"payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
|
|
799
|
+
"levelIndicator": 1,
|
|
800
|
+
"save_account": 1,
|
|
801
|
+
"payment_method": "ach"
|
|
802
|
+
]
|
|
803
|
+
|
|
804
|
+
if let customerId = customerId {
|
|
805
|
+
params["customer"] = customerId
|
|
806
|
+
} else {
|
|
807
|
+
params["username"] = emailPrefix
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
print(params)
|
|
811
|
+
|
|
812
|
+
do {
|
|
813
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
814
|
+
request.httpBody = jsonData
|
|
815
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
816
|
+
print("JSON Payload: \(jsonString)")
|
|
817
|
+
}
|
|
818
|
+
} catch let error {
|
|
819
|
+
print("Error creating JSON data: \(error)")
|
|
820
|
+
hideLoadingIndicator()
|
|
821
|
+
return
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
let session = URLSession.shared
|
|
825
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
826
|
+
|
|
827
|
+
DispatchQueue.main.async {
|
|
828
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if let error = error {
|
|
832
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
833
|
+
return
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
837
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
838
|
+
return
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
842
|
+
if let data = serviceData {
|
|
843
|
+
do {
|
|
844
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
845
|
+
print("Response Data: \(responseObject)")
|
|
846
|
+
|
|
847
|
+
// Check if status is 0 and handle the error
|
|
848
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
849
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
850
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
851
|
+
} else {
|
|
852
|
+
DispatchQueue.main.async {
|
|
853
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
854
|
+
paymentDoneVC.chargeData = responseObject
|
|
855
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
856
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
857
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
} else {
|
|
862
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
863
|
+
}
|
|
864
|
+
} catch let jsonError {
|
|
865
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
869
|
+
}
|
|
870
|
+
} else {
|
|
871
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
task.resume()
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
@IBAction func actionBtnCancel(_ sender: UIButton) {
|
|
878
|
+
stopTimer()
|
|
879
|
+
for viewController in self.navigationController?.viewControllers ?? [] {
|
|
880
|
+
if viewController is PaymentInfoVC {
|
|
881
|
+
self.navigationController?.popToViewController(viewController, animated: true)
|
|
882
|
+
break
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
@IBAction func actionBtnResendOTP(_ sender: UIButton) {
|
|
888
|
+
startTimer()
|
|
889
|
+
btnResendOTP.isHidden = true
|
|
890
|
+
imgEsclamationMark.isHidden = false
|
|
891
|
+
lblOtpTimer.isHidden = false
|
|
892
|
+
lblUntillResendOtp.isHidden = false
|
|
893
|
+
|
|
894
|
+
// Call email verification APi
|
|
895
|
+
emailVerificationApi()
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
@IBAction func actionBtnConfirmCode(_ sender: UIButton) {
|
|
899
|
+
otpVerificationApi()
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
extension OTPVerificationVC: UITextFieldDelegate {
|
|
905
|
+
|
|
906
|
+
func textFieldDidChangeSelection(_ textField: UITextField) {
|
|
907
|
+
guard let otpCode = textField.text, otpCode.count >= 6, textField.textContentType == .oneTimeCode else { return }
|
|
908
|
+
txtFieldOTPText1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
|
|
909
|
+
txtFieldOTPText2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
|
|
910
|
+
txtFieldOTPText3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
|
|
911
|
+
txtFieldOTPText4.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
|
|
912
|
+
txtFieldOTPText5.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 4)])
|
|
913
|
+
txtFieldOTPText6.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 5)])
|
|
914
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
918
|
+
if [txtFieldOTPText1, txtFieldOTPText2, txtFieldOTPText3, txtFieldOTPText4, txtFieldOTPText5, txtFieldOTPText6].contains(textField) {
|
|
919
|
+
if string.count == 1 {
|
|
920
|
+
// Single character input
|
|
921
|
+
textField.text = string
|
|
922
|
+
switch textField {
|
|
923
|
+
case txtFieldOTPText1:
|
|
924
|
+
txtFieldOTPText2.becomeFirstResponder()
|
|
925
|
+
case txtFieldOTPText2:
|
|
926
|
+
txtFieldOTPText3.becomeFirstResponder()
|
|
927
|
+
case txtFieldOTPText3:
|
|
928
|
+
txtFieldOTPText4.becomeFirstResponder()
|
|
929
|
+
case txtFieldOTPText4:
|
|
930
|
+
txtFieldOTPText5.becomeFirstResponder()
|
|
931
|
+
case txtFieldOTPText5:
|
|
932
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
933
|
+
case txtFieldOTPText6:
|
|
934
|
+
txtFieldOTPText6.resignFirstResponder()
|
|
935
|
+
// Call OTP verification API when the last field is filled
|
|
936
|
+
if getCombinedOTP().count == 6 {
|
|
937
|
+
// otpVerificationApi()
|
|
938
|
+
}
|
|
939
|
+
default:
|
|
940
|
+
break
|
|
941
|
+
}
|
|
942
|
+
updateViewColors()
|
|
943
|
+
return false
|
|
944
|
+
} else if string.isEmpty {
|
|
945
|
+
// Handle backspace
|
|
946
|
+
textField.text = ""
|
|
947
|
+
switch textField {
|
|
948
|
+
case txtFieldOTPText6:
|
|
949
|
+
txtFieldOTPText5.becomeFirstResponder()
|
|
950
|
+
case txtFieldOTPText5:
|
|
951
|
+
txtFieldOTPText4.becomeFirstResponder()
|
|
952
|
+
case txtFieldOTPText4:
|
|
953
|
+
txtFieldOTPText3.becomeFirstResponder()
|
|
954
|
+
case txtFieldOTPText3:
|
|
955
|
+
txtFieldOTPText2.becomeFirstResponder()
|
|
956
|
+
case txtFieldOTPText2:
|
|
957
|
+
txtFieldOTPText1.becomeFirstResponder()
|
|
958
|
+
default:
|
|
959
|
+
break
|
|
960
|
+
}
|
|
961
|
+
updateViewColors()
|
|
962
|
+
return false
|
|
963
|
+
}
|
|
964
|
+
return textField.text?.count == 0
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
return true
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Update the view colors based on text presence in OTP fields.
|
|
971
|
+
private func updateViewColors() {
|
|
972
|
+
viewTextOTP1.backgroundColor = txtFieldOTPText1.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
973
|
+
viewTextOTP2.backgroundColor = txtFieldOTPText2.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
974
|
+
viewTextOTP3.backgroundColor = txtFieldOTPText3.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
975
|
+
viewTextOTP4.backgroundColor = txtFieldOTPText4.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
976
|
+
viewTextOTP5.backgroundColor = txtFieldOTPText5.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
977
|
+
viewTextOTP6.backgroundColor = txtFieldOTPText6.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
@objc func textFieldDidChange(_ textField: UITextField) {
|
|
981
|
+
guard let otpCode = textField.text, otpCode.count >= 6, textField.textContentType == .oneTimeCode else { return }
|
|
982
|
+
// Split the OTP into each text field
|
|
983
|
+
txtFieldOTPText1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
|
|
984
|
+
txtFieldOTPText2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
|
|
985
|
+
txtFieldOTPText3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
|
|
986
|
+
txtFieldOTPText4.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
|
|
987
|
+
txtFieldOTPText5.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 4)])
|
|
988
|
+
txtFieldOTPText6.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 5)])
|
|
989
|
+
// Automatically move to the last text field
|
|
990
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
func getCombinedOTP() -> String {
|
|
994
|
+
let otp1 = txtFieldOTPText1.text ?? ""
|
|
995
|
+
let otp2 = txtFieldOTPText2.text ?? ""
|
|
996
|
+
let otp3 = txtFieldOTPText3.text ?? ""
|
|
997
|
+
let otp4 = txtFieldOTPText4.text ?? ""
|
|
998
|
+
let otp5 = txtFieldOTPText5.text ?? ""
|
|
999
|
+
let otp6 = txtFieldOTPText6.text ?? ""
|
|
1000
|
+
|
|
1001
|
+
return otp1 + otp2 + otp3 + otp4 + otp5 + otp6
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
|