@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.
Files changed (188) hide show
  1. package/.idea/caches/deviceStreaming.xml +340 -0
  2. package/.idea/em-MobileCheckoutSDK-ReactNative.iml +9 -0
  3. package/.idea/misc.xml +5 -0
  4. package/.idea/modules.xml +8 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/README.md +230 -0
  7. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/results.bin +1 -0
  8. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
  9. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  10. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  11. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
  12. package/android/build/.transforms/27d3a0c22098810ca42038b1b8102417/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  13. package/android/build/.transforms/41cd2635778c1bb5c18af2c46eb9196e/results.bin +1 -0
  14. package/android/build/.transforms/41cd2635778c1bb5c18af2c46eb9196e/transformed/classes/classes_dex/classes.dex +0 -0
  15. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/results.bin +1 -0
  16. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
  17. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  18. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  19. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
  20. package/android/build/.transforms/6b36622787f586c4b6e3df98c5efa11c/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  21. package/android/build/.transforms/7eb7ceaa43c9e8323ac65b4f785987b6/results.bin +1 -0
  22. package/android/build/.transforms/7eb7ceaa43c9e8323ac65b4f785987b6/transformed/classes/classes_dex/classes.dex +0 -0
  23. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/results.bin +1 -0
  24. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
  25. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  26. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  27. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
  28. package/android/build/.transforms/a8b93af4be449a0e2cca4bd6ddb6685e/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  29. package/android/build/.transforms/f1a160720415bc76d8d6c6734c5acf3e/results.bin +1 -0
  30. package/android/build/.transforms/f1a160720415bc76d8d6c6734c5acf3e/transformed/classes/classes_dex/classes.dex +0 -0
  31. package/android/build/generated/source/buildConfig/debug/com/reactlibrary/BuildConfig.java +10 -0
  32. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +7 -0
  33. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
  34. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
  35. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
  36. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  37. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  38. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  39. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  40. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  41. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  42. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  43. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  44. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/BuildConfig.class +0 -0
  45. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  46. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  47. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
  48. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
  49. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +7 -0
  50. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +7 -0
  51. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
  52. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
  53. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/BuildConfig.class +0 -0
  54. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  55. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  56. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
  57. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  58. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
  59. package/android/build/outputs/logs/manifest-merger-debug-report.txt +17 -0
  60. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId2 +0 -0
  61. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId1 +0 -0
  62. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId0 +0 -0
  63. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  64. package/android/build.gradle +55 -0
  65. package/android/src/main/AndroidManifest.xml +5 -0
  66. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +72 -0
  67. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkPackage.java +28 -0
  68. package/index.js +5 -0
  69. package/ios/Bundle/EasyPayBundle.swift +22 -0
  70. package/ios/Classes/EasyMerchantSdk.h +4 -0
  71. package/ios/Classes/EasyMerchantSdk.m +43 -0
  72. package/ios/Classes/EasyMerchantSdk.swift +124 -0
  73. package/ios/Classes/EasyPayViewController.swift +90 -0
  74. package/ios/CustomComponents/CheckboxButton.swift +20 -0
  75. package/ios/CustomComponents/FilledButton.swift +17 -0
  76. package/ios/CustomComponents/OutlineButton.swift +26 -0
  77. package/ios/CustomComponents/TextFieldStackView.swift +96 -0
  78. package/ios/EnvironmentConfig.swift +63 -0
  79. package/ios/Example/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  80. package/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
  81. package/ios/Example/Assets.xcassets/Contents.json +6 -0
  82. package/ios/Example/Base.lproj/LaunchScreen.storyboard +25 -0
  83. package/ios/Example/Base.lproj/Main.storyboard +65 -0
  84. package/ios/Example/SceneDelegate.swift +52 -0
  85. package/ios/Example/ViewController.swift +84 -0
  86. package/ios/Extensions/UIColor.swift +22 -0
  87. package/ios/Extensions/UIFont.swift +80 -0
  88. package/ios/Extensions/UIViewController+Extension.swift +42 -0
  89. package/ios/Models/AdditionalInfo.swift +16 -0
  90. package/ios/Models/BankAccountModel.swift +23 -0
  91. package/ios/Models/BillingInfo.swift +16 -0
  92. package/ios/Models/CardModel.swift +19 -0
  93. package/ios/Models/Country.swift +19 -0
  94. package/ios/Models/PaymentInfo.swift +46 -0
  95. package/ios/Models/Request.swift +245 -0
  96. package/ios/Models/Result.swift +69 -0
  97. package/ios/Pods/UserDefaults/UserStoreSingleton.swift +200 -0
  98. package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +1073 -0
  99. package/ios/Pods/ViewControllers/BaseVC.swift +117 -0
  100. package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +616 -0
  101. package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CityListTVC.swift +19 -0
  102. package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CountryListTVC.swift +19 -0
  103. package/ios/Pods/ViewControllers/BillingInfoVC/Cells/StateListTVC.swift +19 -0
  104. package/ios/Pods/ViewControllers/CountryListVC.swift +367 -0
  105. package/ios/Pods/ViewControllers/EmailVerificationVC.swift +192 -0
  106. package/ios/Pods/ViewControllers/OTPVerificationVC.swift +1009 -0
  107. package/ios/Pods/ViewControllers/PaymentDoneVC.swift +94 -0
  108. package/ios/Pods/ViewControllers/PaymentErrorVC.swift +43 -0
  109. package/ios/Pods/ViewControllers/PaymentInformation/AccountTypeTVC.swift +19 -0
  110. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +4269 -0
  111. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInformationCVC.swift +20 -0
  112. package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.swift +37 -0
  113. package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.xib +163 -0
  114. package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.swift +40 -0
  115. package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.xib +184 -0
  116. package/ios/Pods/ViewControllers/TermAndConditionsVC.swift +21 -0
  117. package/ios/Resources/Assets.xcassets/Card/Amex.imageset/206682_american_express_method_card_payment_icon.svg +1 -0
  118. package/ios/Resources/Assets.xcassets/Card/Amex.imageset/Contents.json +12 -0
  119. package/ios/Resources/Assets.xcassets/Card/Contents.json +6 -0
  120. package/ios/Resources/Assets.xcassets/Card/DinersClub.imageset/472318_card_club_diners_dinner_payment_icon.svg +1 -0
  121. package/ios/Resources/Assets.xcassets/Card/DinersClub.imageset/Contents.json +12 -0
  122. package/ios/Resources/Assets.xcassets/Card/Discover.imageset/206686_network_payment_discover_card_method_icon.svg +1 -0
  123. package/ios/Resources/Assets.xcassets/Card/Discover.imageset/Contents.json +12 -0
  124. package/ios/Resources/Assets.xcassets/Card/JCB.imageset/358102_card_jcb_payment_icon.svg +1 -0
  125. package/ios/Resources/Assets.xcassets/Card/JCB.imageset/Contents.json +12 -0
  126. package/ios/Resources/Assets.xcassets/Card/MasterCard.imageset/206680_master_method_card_payment_icon.svg +1 -0
  127. package/ios/Resources/Assets.xcassets/Card/MasterCard.imageset/Contents.json +12 -0
  128. package/ios/Resources/Assets.xcassets/Card/UnionPay.imageset/1468976_card_payment_unionpay_icon.svg +1 -0
  129. package/ios/Resources/Assets.xcassets/Card/UnionPay.imageset/Contents.json +12 -0
  130. package/ios/Resources/Assets.xcassets/Card/Visa.imageset/206684_visa_method_card_payment_icon.svg +1 -0
  131. package/ios/Resources/Assets.xcassets/Card/Visa.imageset/Contents.json +12 -0
  132. package/ios/Resources/Assets.xcassets/Card/maestro.imageset/Contents.json +12 -0
  133. package/ios/Resources/Assets.xcassets/Card/maestro.imageset/maestro.svg +1 -0
  134. package/ios/Resources/Assets.xcassets/Card/paypal.imageset/206675_paypal_method_payment_icon.svg +1 -0
  135. package/ios/Resources/Assets.xcassets/Card/paypal.imageset/Contents.json +12 -0
  136. package/ios/Resources/Assets.xcassets/Card/rupay.imageset/Contents.json +12 -0
  137. package/ios/Resources/Assets.xcassets/Card/rupay.imageset/rupay.svg +1 -0
  138. package/ios/Resources/Assets.xcassets/Card/unknown_card.imageset/4635000_card_credit_digital_money_icon.svg +1 -0
  139. package/ios/Resources/Assets.xcassets/Card/unknown_card.imageset/Contents.json +12 -0
  140. package/ios/Resources/Assets.xcassets/Card/worldpay.imageset/Contents.json +12 -0
  141. package/ios/Resources/Assets.xcassets/Card/worldpay.imageset/worldpay.svg +1 -0
  142. package/ios/Resources/Assets.xcassets/Contents.json +6 -0
  143. package/ios/Resources/Assets.xcassets/Ellipsis.imageset/Contents.json +23 -0
  144. package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-30.png +0 -0
  145. package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-60.png +0 -0
  146. package/ios/Resources/Assets.xcassets/Ellipsis.imageset/icons8-menu-90.png +0 -0
  147. package/ios/Resources/Assets.xcassets/Rotate.imageset/Contents.json +23 -0
  148. package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw-2.png +0 -0
  149. package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw-3.png +0 -0
  150. package/ios/Resources/Assets.xcassets/Rotate.imageset/refresh-cw.png +0 -0
  151. package/ios/Resources/Assets.xcassets/amexCvc.imageset/Contents.json +22 -0
  152. package/ios/Resources/Assets.xcassets/amexCvc.imageset/Group-1.png +0 -0
  153. package/ios/Resources/Assets.xcassets/amexCvc.imageset/Group.png +0 -0
  154. package/ios/Resources/Assets.xcassets/check.imageset/Contents.json +23 -0
  155. package/ios/Resources/Assets.xcassets/check.imageset/check-circle-4.png +0 -0
  156. package/ios/Resources/Assets.xcassets/check.imageset/check-circle-5.png +0 -0
  157. package/ios/Resources/Assets.xcassets/check.imageset/check-circle-6.png +0 -0
  158. package/ios/Resources/Assets.xcassets/chip.imageset/Contents.json +21 -0
  159. package/ios/Resources/Assets.xcassets/chip.imageset/chip.png +0 -0
  160. package/ios/Resources/Assets.xcassets/loaderImage.imageset/Contents.json +23 -0
  161. package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle-2.png +0 -0
  162. package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle-3.png +0 -0
  163. package/ios/Resources/Assets.xcassets/loaderImage.imageset/check-circle.png +0 -0
  164. package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/Contents.json +23 -0
  165. package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon 1.png +0 -0
  166. package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon 2.png +0 -0
  167. package/ios/Resources/Assets.xcassets/payment_done_icon.imageset/payment_done_icon.png +0 -0
  168. package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/Contents.json +23 -0
  169. package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon 1.png +0 -0
  170. package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon 2.png +0 -0
  171. package/ios/Resources/Assets.xcassets/payment_error_icon.imageset/payment_error_icon.png +0 -0
  172. package/ios/Resources/Assets.xcassets/wallet.imageset/Contents.json +23 -0
  173. package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-24(@1/303/227).png +0 -0
  174. package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-48(@2/303/227).png +0 -0
  175. package/ios/Resources/Assets.xcassets/wallet.imageset/icons8-wallet-72(@3/303/227).png +0 -0
  176. package/ios/Resources/Colors.xcassets/00000008.colorset/Contents.json +20 -0
  177. package/ios/Resources/Colors.xcassets/00000016.colorset/Contents.json +20 -0
  178. package/ios/Resources/Colors.xcassets/00000038.colorset/Contents.json +20 -0
  179. package/ios/Resources/Colors.xcassets/00000060.colorset/Contents.json +20 -0
  180. package/ios/Resources/Colors.xcassets/1757D9.colorset/Contents.json +20 -0
  181. package/ios/Resources/Colors.xcassets/Contents.json +6 -0
  182. package/ios/Resources/Colors.xcassets/E93939.colorset/Contents.json +20 -0
  183. package/ios/Resources/PrivacyInfo.xcprivacy +10 -0
  184. package/ios/ThirdParty/Keyboad Handling/KeyboardObserver.swift +74 -0
  185. package/ios/easymerchantsdk.podspec +80 -0
  186. package/ios/easymerchantsdk.storyboard +5885 -0
  187. package/package.json +27 -0
  188. 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
+