@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,4269 @@
|
|
|
1
|
+
//
|
|
2
|
+
// PaymentInfoVC.swift
|
|
3
|
+
// EasyPay
|
|
4
|
+
//
|
|
5
|
+
// Created by Mony's Mac on 06/09/24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
|
|
10
|
+
struct PaymentsData {
|
|
11
|
+
var name = String()
|
|
12
|
+
var image = String()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let EasyPaySdk = UIStoryboard(name: "EasyPaySdk", bundle: Bundle.easyPayBundle)
|
|
16
|
+
|
|
17
|
+
class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
18
|
+
|
|
19
|
+
@IBOutlet weak var viewBtnShowSavedCards: UIView!
|
|
20
|
+
@IBOutlet weak var viewBtnShowSavedCardHeight: NSLayoutConstraint!
|
|
21
|
+
@IBOutlet weak var viewBtnShowSavedCardTopCon: NSLayoutConstraint!
|
|
22
|
+
@IBOutlet weak var lblBtnShowSaveCard: UILabel!
|
|
23
|
+
|
|
24
|
+
@IBOutlet weak var collVwPayment: UICollectionView!
|
|
25
|
+
|
|
26
|
+
@IBOutlet weak var viewCardFields: UIView!
|
|
27
|
+
|
|
28
|
+
@IBOutlet weak var btnNext: FilledButton!
|
|
29
|
+
@IBOutlet weak var btnNextHeight: NSLayoutConstraint!
|
|
30
|
+
@IBOutlet weak var btnNextTopCon: NSLayoutConstraint!
|
|
31
|
+
|
|
32
|
+
@IBOutlet weak var btnCheckBoxSavedCard: UIButton!
|
|
33
|
+
@IBOutlet weak var lblEasyMerchantOne: UILabel!
|
|
34
|
+
@IBOutlet weak var btnSettings: UIButton!
|
|
35
|
+
|
|
36
|
+
// Card
|
|
37
|
+
@IBOutlet private var cardNumberTextField: TextFieldStackView!
|
|
38
|
+
@IBOutlet private var cardExpiryTextField: TextFieldStackView!
|
|
39
|
+
@IBOutlet private var cardCvvTextField: TextFieldStackView!
|
|
40
|
+
@IBOutlet private var cardNameTextField: TextFieldStackView!
|
|
41
|
+
@IBOutlet weak var viewTextFieldCardNumber: UIView!
|
|
42
|
+
@IBOutlet weak var viewTxtFieldExpiryDate: UIView!
|
|
43
|
+
@IBOutlet weak var viewTxtFieldCVV: UIView!
|
|
44
|
+
@IBOutlet weak var viewTxtFieldNameOnCard: UIView!
|
|
45
|
+
|
|
46
|
+
@IBOutlet weak var emailView: UIView!
|
|
47
|
+
@IBOutlet weak var txtFieldEmail: UITextField!
|
|
48
|
+
@IBOutlet weak var viewTxtFieldEmail: UIView!
|
|
49
|
+
@IBOutlet weak var OTPView: UIView!
|
|
50
|
+
|
|
51
|
+
//OTP View
|
|
52
|
+
@IBOutlet weak var viewTextOTP1: UIView!
|
|
53
|
+
@IBOutlet weak var txtFieldOTPText1: UITextField!
|
|
54
|
+
@IBOutlet weak var viewTextOTP2: UIView!
|
|
55
|
+
@IBOutlet weak var txtFieldOTPText2: UITextField!
|
|
56
|
+
@IBOutlet weak var viewTextOTP3: UIView!
|
|
57
|
+
@IBOutlet weak var txtFieldOTPText3: UITextField!
|
|
58
|
+
@IBOutlet weak var viewTextOTP4: UIView!
|
|
59
|
+
@IBOutlet weak var txtFieldOTPText4: UITextField!
|
|
60
|
+
@IBOutlet weak var viewTextOTP5: UIView!
|
|
61
|
+
@IBOutlet weak var txtFieldOTPText5: UITextField!
|
|
62
|
+
@IBOutlet weak var viewTextOTP6: UIView!
|
|
63
|
+
@IBOutlet weak var txtFieldOTPText6: UITextField!
|
|
64
|
+
@IBOutlet weak var imgEsclamationMark: UIImageView!
|
|
65
|
+
@IBOutlet weak var lblOtpTimer: UILabel!
|
|
66
|
+
@IBOutlet weak var lblUntillResendOtp: UILabel!
|
|
67
|
+
@IBOutlet weak var btnResendOTP: UIButton!
|
|
68
|
+
|
|
69
|
+
@IBOutlet private var buttonBottomConstraint: NSLayoutConstraint!
|
|
70
|
+
|
|
71
|
+
//Single Saved Card
|
|
72
|
+
@IBOutlet weak var viewSingleSavedCard: UIView!
|
|
73
|
+
@IBOutlet weak var viewSingleSavedCardHeight: NSLayoutConstraint!
|
|
74
|
+
@IBOutlet weak var viewTxtFieldCVVSingleCard: TextFieldStackView!
|
|
75
|
+
@IBOutlet weak var txtFieldCVVSingleSavedCard: UITextField!
|
|
76
|
+
@IBOutlet weak var viewTxtFieldCVVSingleSavedCard: UIView!
|
|
77
|
+
@IBOutlet weak var btnPayNowSingleCard: FilledButton!
|
|
78
|
+
@IBOutlet weak var imgViewSigleSavedCard: UIImageView!
|
|
79
|
+
@IBOutlet weak var lblCardNumberSigleSavedCard: UILabel!
|
|
80
|
+
@IBOutlet weak var lblExpireDateSingelSavedCard: UILabel!
|
|
81
|
+
|
|
82
|
+
@IBOutlet weak var viewChangeCard: UIView!
|
|
83
|
+
@IBOutlet weak var viewUpdateCard: UIView!
|
|
84
|
+
@IBOutlet weak var viewAddNewCard: UIView!
|
|
85
|
+
|
|
86
|
+
@IBOutlet weak var tblViewSavedCardsList: UITableView!
|
|
87
|
+
@IBOutlet weak var tblViewSavedCardListHeight: NSLayoutConstraint!
|
|
88
|
+
|
|
89
|
+
//Update Card
|
|
90
|
+
@IBOutlet weak var btnSelectUpdateCardView: UIButton!
|
|
91
|
+
@IBOutlet weak var imgViewCardUpdateCardView: UIImageView!
|
|
92
|
+
@IBOutlet weak var lblCardNumberUpdateCardView: UILabel!
|
|
93
|
+
@IBOutlet weak var lblExpireDateUpdateCardView: UILabel!
|
|
94
|
+
@IBOutlet weak var txtFieldExpireDateUpdateCardView: UITextField!
|
|
95
|
+
@IBOutlet weak var viewTxtFieldExpireDateUpdateCardView: UIView!
|
|
96
|
+
@IBOutlet weak var txtFieldCVVUpdateCardView: UITextField!
|
|
97
|
+
@IBOutlet weak var viewtxtFieldCVVUpdateCardView: UIView!
|
|
98
|
+
@IBOutlet weak var txtFieldNameOnCardUpdateCardView: UITextField!
|
|
99
|
+
@IBOutlet weak var viewTxtFieldNameOnCardUpdateCardView: UIView!
|
|
100
|
+
|
|
101
|
+
//New Card
|
|
102
|
+
@IBOutlet weak var txtFieldCardNumberNewCardView: UITextField!
|
|
103
|
+
@IBOutlet weak var viewtxtFieldCardNumberNewCardView: UIView!
|
|
104
|
+
@IBOutlet weak var txtFieldExpiryDateNewCardView: UITextField!
|
|
105
|
+
@IBOutlet weak var viewtxtFieldExpiryDateNewCardView: UIView!
|
|
106
|
+
@IBOutlet weak var txtFieldCVVNewCardView: UITextField!
|
|
107
|
+
@IBOutlet weak var viewtxtFieldCVVNewCardView: UIView!
|
|
108
|
+
@IBOutlet weak var txtFieldNameOnCardNewCardView: UITextField!
|
|
109
|
+
@IBOutlet weak var viewtxtFieldNameOnCardNewCardView: UIView!
|
|
110
|
+
@IBOutlet weak var btnPayNowNewCardView: FilledButton!
|
|
111
|
+
@IBOutlet weak var btnSavedCardForFutureNewCardView: CheckboxButton!
|
|
112
|
+
|
|
113
|
+
//Bank
|
|
114
|
+
@IBOutlet weak var viewBankFields: UIView!
|
|
115
|
+
@IBOutlet weak var txtFieldAccountName: UITextField!
|
|
116
|
+
@IBOutlet weak var viewtxtFieldAccountName: UIView!
|
|
117
|
+
@IBOutlet weak var txtFieldRoutingNumber: UITextField!
|
|
118
|
+
@IBOutlet weak var viewtxtFieldRoutingNumber: UIView!
|
|
119
|
+
@IBOutlet weak var txtFieldAccountType: UITextField!
|
|
120
|
+
@IBOutlet weak var viewtxtFieldAccountType: UIView!
|
|
121
|
+
@IBOutlet weak var txtFieldAccountNumber: UITextField!
|
|
122
|
+
@IBOutlet weak var viewtxtFieldAccountNumber: UIView!
|
|
123
|
+
@IBOutlet weak var viewTermsAndConditions: UIStackView!
|
|
124
|
+
@IBOutlet weak var btnAgreeTermsConditions: UIButton!
|
|
125
|
+
@IBOutlet weak var lblTermsAndConditions: UILabel!
|
|
126
|
+
@IBOutlet weak var viewAccountType: UIView!
|
|
127
|
+
@IBOutlet weak var tblViewAccountTypes: UITableView!
|
|
128
|
+
@IBOutlet weak var btnCheckSavedAccountForFuture: UIButton!
|
|
129
|
+
|
|
130
|
+
//SavedBank
|
|
131
|
+
@IBOutlet weak var viewSingleSavedAccount: UIView!
|
|
132
|
+
@IBOutlet weak var viewTermAndConditionsSingleAccountView: UIStackView!
|
|
133
|
+
@IBOutlet weak var btnCheckAgreeTermsAndConditionsSingleAccount: UIButton!
|
|
134
|
+
@IBOutlet weak var lblTermsAndCondtionsSingleAccount: UILabel!
|
|
135
|
+
@IBOutlet weak var lblAgreetoTheSingleSavedAccountView: UILabel!
|
|
136
|
+
@IBOutlet weak var btnSelectSingleAccountView: UIButton!
|
|
137
|
+
@IBOutlet weak var lblAccountNumberSingleAccountView: UILabel!
|
|
138
|
+
@IBOutlet weak var lblAccountTypeSingleAccountView: UILabel!
|
|
139
|
+
@IBOutlet weak var btnPayNowSingleAccountView: FilledButton!
|
|
140
|
+
@IBOutlet weak var viewSingleAccountViewHeight: NSLayoutConstraint!
|
|
141
|
+
@IBOutlet weak var viewChangedAccount: UIView!
|
|
142
|
+
@IBOutlet weak var tblViewSavedBankAccounts: UITableView!
|
|
143
|
+
@IBOutlet weak var tblViewSavedBankAccountsHeight: NSLayoutConstraint!
|
|
144
|
+
|
|
145
|
+
//New Bank
|
|
146
|
+
@IBOutlet weak var viewNewBankAccount: UIView!
|
|
147
|
+
@IBOutlet weak var txtFieldAccountNameNewAccountView: UITextField!
|
|
148
|
+
@IBOutlet weak var viewtxtFieldAccountNameNewAccountView: UIView!
|
|
149
|
+
@IBOutlet weak var txtFieldRoutingNumberNewAccountView: UITextField!
|
|
150
|
+
@IBOutlet weak var viewtxtFieldRoutingNumberNewAccountView: UIView!
|
|
151
|
+
@IBOutlet weak var txtFieldAccountTypeNewAccountView: UITextField!
|
|
152
|
+
@IBOutlet weak var viewtxtFieldAccountTypeNewAccountView: UIView!
|
|
153
|
+
@IBOutlet weak var txtFieldAccountNumberNewAccountView: UITextField!
|
|
154
|
+
@IBOutlet weak var viewtxtFieldAccountNumberNewAccountView: UIView!
|
|
155
|
+
@IBOutlet weak var btnSavedNewAccountForFuture: UIButton!
|
|
156
|
+
@IBOutlet weak var viewAccountTypeNewAccountView: UIView!
|
|
157
|
+
@IBOutlet weak var tblViewAccountTypeNewAccountView: UITableView!
|
|
158
|
+
@IBOutlet weak var btnPayNowNewAccountView: FilledButton!
|
|
159
|
+
|
|
160
|
+
//Crypto
|
|
161
|
+
@IBOutlet weak var viewCrypto: UIView!
|
|
162
|
+
@IBOutlet weak var viewCryptoTryAgain: UIView!
|
|
163
|
+
@IBOutlet weak var viewCryptoQRCode: UIView!
|
|
164
|
+
@IBOutlet weak var qrImageView: UIImageView!
|
|
165
|
+
@IBOutlet weak var lblAmmoutCrypto: UILabel!
|
|
166
|
+
@IBOutlet weak var lblCryptoAmmountViewTryAgain: UILabel!
|
|
167
|
+
@IBOutlet weak var lblTimerCrypto: UILabel!
|
|
168
|
+
@IBOutlet weak var btnOnChain: UIButton!
|
|
169
|
+
@IBOutlet weak var btnLightning: UIButton!
|
|
170
|
+
@IBOutlet weak var lblBTCAddress: UILabel!
|
|
171
|
+
@IBOutlet weak var viewQrTryAgainHeight: NSLayoutConstraint!
|
|
172
|
+
@IBOutlet weak var viewQrCodeHeight: NSLayoutConstraint!
|
|
173
|
+
@IBOutlet weak var viewCryptoHeight: NSLayoutConstraint!
|
|
174
|
+
|
|
175
|
+
//Setting View
|
|
176
|
+
@IBOutlet weak var settingsView: UIView!
|
|
177
|
+
|
|
178
|
+
var chainInvoiceAddress: String?
|
|
179
|
+
var lightningURI: String?
|
|
180
|
+
|
|
181
|
+
var cryptoTimer: DispatchSourceTimer?
|
|
182
|
+
var totalTimeInSeconds = 300 // 5 minutes (300 seconds)
|
|
183
|
+
var isTimerRunning = false
|
|
184
|
+
|
|
185
|
+
var chargeId: String?
|
|
186
|
+
var cryptoInfoTimer: Timer?
|
|
187
|
+
|
|
188
|
+
var savedCards: [CardModel] = []
|
|
189
|
+
var isSelectForPay: Bool = false
|
|
190
|
+
|
|
191
|
+
var selectedCardIndex: Int? = nil
|
|
192
|
+
|
|
193
|
+
private var request: Request!
|
|
194
|
+
private weak var delegate: EasyPayViewControllerDelegate?
|
|
195
|
+
|
|
196
|
+
public var amount: Int?
|
|
197
|
+
|
|
198
|
+
let arrPaymentMethods = [
|
|
199
|
+
PaymentsData(name: "Card",image: "creditcard"),
|
|
200
|
+
PaymentsData(name: "Bank",image: "building.columns.fill"),
|
|
201
|
+
PaymentsData(name: "Crypto",image: "bitcoinsign.circle.fill"),
|
|
202
|
+
PaymentsData(name: "Wallet",image: "bag.fill")
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
private var selectedIndex: IndexPath?
|
|
206
|
+
var selectedPaymentMethod: String?
|
|
207
|
+
|
|
208
|
+
private var timer: Timer?
|
|
209
|
+
private var timeRemaining = 180 // 3 minutes
|
|
210
|
+
|
|
211
|
+
var isSavedForFuture: Bool = false
|
|
212
|
+
|
|
213
|
+
var selectedCard: CardModel?
|
|
214
|
+
|
|
215
|
+
var isSavedNewCardForFuture: Bool = false
|
|
216
|
+
|
|
217
|
+
var selectedCardID: String?
|
|
218
|
+
|
|
219
|
+
//Bank
|
|
220
|
+
var bankAccounts: [Accounts] = []
|
|
221
|
+
var selectedbankAccounts: Accounts?
|
|
222
|
+
var selectedBank: BankAccountModel?
|
|
223
|
+
var isSelectForPayBank: Bool = false
|
|
224
|
+
var selectedBankIndex: Int? = nil
|
|
225
|
+
var arrAccountType = ["Saving","Current"]
|
|
226
|
+
|
|
227
|
+
var agreeTermsAndCondtition: Bool = false
|
|
228
|
+
|
|
229
|
+
var isSavedNewAccount: Bool = false
|
|
230
|
+
var selectedBankID: String?
|
|
231
|
+
|
|
232
|
+
public weak var easyPayDelegate: EasyPayViewControllerDelegate?
|
|
233
|
+
|
|
234
|
+
private let keyboardObserver = KeyboardObserver()
|
|
235
|
+
|
|
236
|
+
var isFrom = String()
|
|
237
|
+
|
|
238
|
+
//MARK: - View Did Load
|
|
239
|
+
override func viewDidLoad() {
|
|
240
|
+
super.viewDidLoad()
|
|
241
|
+
|
|
242
|
+
viewCryptoTryAgain.layer.borderColor = UIColor.systemGray.cgColor
|
|
243
|
+
viewCryptoTryAgain.layer.borderWidth = 1
|
|
244
|
+
viewCryptoTryAgain.layer.cornerRadius = 8
|
|
245
|
+
|
|
246
|
+
viewCryptoQRCode.layer.borderColor = UIColor.systemGray.cgColor
|
|
247
|
+
viewCryptoQRCode.layer.borderWidth = 1
|
|
248
|
+
viewCryptoQRCode.layer.cornerRadius = 8
|
|
249
|
+
|
|
250
|
+
setUpTextFieldsDelegates()
|
|
251
|
+
|
|
252
|
+
collVwPayment.delegate = self
|
|
253
|
+
collVwPayment.dataSource = self
|
|
254
|
+
// Set the first cell as selected by default
|
|
255
|
+
selectedIndex = IndexPath(row: 0, section: 0)
|
|
256
|
+
selectedPaymentMethod = arrPaymentMethods[selectedIndex!.row].name
|
|
257
|
+
collVwPayment.reloadData()
|
|
258
|
+
|
|
259
|
+
// Add tap gesture to hide the keyboard when tapping outside of text fields
|
|
260
|
+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
|
|
261
|
+
tapGesture.cancelsTouchesInView = false
|
|
262
|
+
self.view.addGestureRecognizer(tapGesture)
|
|
263
|
+
|
|
264
|
+
// Check if billingInfoData is available
|
|
265
|
+
if let billingInfoData = request.billingInfoData,
|
|
266
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
267
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
|
|
268
|
+
print("Billing Info Data: \(jsonDict)")
|
|
269
|
+
// Set the button title to the default "Next"
|
|
270
|
+
btnNext.setTitle("Next (Billing Info)", for: .normal)
|
|
271
|
+
btnPayNowNewCardView.setTitle("Next (Billing Info)", for: .normal)
|
|
272
|
+
btnPayNowNewAccountView.setTitle("Next (Billing Info)", for: .normal)
|
|
273
|
+
btnPayNowSingleCard.setTitle("Next (Billing Info)", for: .normal)
|
|
274
|
+
btnPayNowSingleAccountView.setTitle("Next (Billing Info)", for: .normal)
|
|
275
|
+
} else {
|
|
276
|
+
// If billingInfoData is nil or empty, set the button title to "Pay Now"
|
|
277
|
+
btnNext.setTitle("Pay Now ($\(amount ?? 0))", for: .normal)
|
|
278
|
+
btnPayNowNewCardView.setTitle("Pay Now ($\(amount ?? 0))", for: .normal)
|
|
279
|
+
btnPayNowNewAccountView.setTitle("Pay Now ($\(amount ?? 0))", for: .normal)
|
|
280
|
+
btnPayNowSingleCard.setTitle("Pay Now ($\(amount ?? 0))", for: .normal)
|
|
281
|
+
btnPayNowSingleAccountView.setTitle("Pay Now ($\(amount ?? 0))", for: .normal)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
emailView.isHidden = true
|
|
285
|
+
OTPView.isHidden = true
|
|
286
|
+
|
|
287
|
+
//OTP View
|
|
288
|
+
btnResendOTP.isHidden = true
|
|
289
|
+
|
|
290
|
+
// Set delegate for txtFieldEmail to handle return key press
|
|
291
|
+
txtFieldEmail.delegate = self
|
|
292
|
+
|
|
293
|
+
setupTextFields()
|
|
294
|
+
|
|
295
|
+
tblViewSavedCardsList.delegate = self
|
|
296
|
+
tblViewSavedCardsList.dataSource = self
|
|
297
|
+
let nib = UINib(nibName: "SavedCardsTVC", bundle: .easyPayBundle)
|
|
298
|
+
tblViewSavedCardsList.register(nib, forCellReuseIdentifier: "SavedCardsTVC")
|
|
299
|
+
tblViewSavedCardsList.showsVerticalScrollIndicator = false
|
|
300
|
+
tblViewSavedCardsList.showsHorizontalScrollIndicator = false
|
|
301
|
+
tblViewSavedCardsList.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
|
|
302
|
+
|
|
303
|
+
viewChangeCard.isHidden = true
|
|
304
|
+
|
|
305
|
+
tblViewSavedBankAccounts.delegate = self
|
|
306
|
+
tblViewSavedBankAccounts.dataSource = self
|
|
307
|
+
let nib2 = UINib(nibName: "SavedAccountTVC", bundle: .easyPayBundle)
|
|
308
|
+
tblViewSavedBankAccounts.register(nib2, forCellReuseIdentifier: "SavedAccountTVC")
|
|
309
|
+
tblViewSavedBankAccounts.showsVerticalScrollIndicator = false
|
|
310
|
+
tblViewSavedBankAccounts.showsHorizontalScrollIndicator = false
|
|
311
|
+
tblViewSavedBankAccounts.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
|
|
312
|
+
|
|
313
|
+
viewChangedAccount.isHidden = true
|
|
314
|
+
|
|
315
|
+
tblViewAccountTypes.delegate = self
|
|
316
|
+
tblViewAccountTypes.dataSource = self
|
|
317
|
+
tblViewAccountTypes.showsVerticalScrollIndicator = false
|
|
318
|
+
tblViewAccountTypes.showsHorizontalScrollIndicator = false
|
|
319
|
+
|
|
320
|
+
viewAccountType.clipsToBounds = false
|
|
321
|
+
viewAccountType.layer.shadowColor = UIColor.black.cgColor
|
|
322
|
+
viewAccountType.layer.shadowOpacity = 0.3
|
|
323
|
+
viewAccountType.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
324
|
+
viewAccountType.layer.shadowRadius = 4
|
|
325
|
+
viewAccountType.layer.cornerRadius = 8
|
|
326
|
+
viewAccountType.layer.cornerRadius = 8
|
|
327
|
+
|
|
328
|
+
viewAccountType.isHidden = true
|
|
329
|
+
|
|
330
|
+
tblViewAccountTypeNewAccountView.delegate = self
|
|
331
|
+
tblViewAccountTypeNewAccountView.dataSource = self
|
|
332
|
+
tblViewAccountTypeNewAccountView.showsVerticalScrollIndicator = false
|
|
333
|
+
tblViewAccountTypeNewAccountView.showsHorizontalScrollIndicator = false
|
|
334
|
+
|
|
335
|
+
viewAccountTypeNewAccountView.clipsToBounds = false
|
|
336
|
+
viewAccountTypeNewAccountView.layer.shadowColor = UIColor.black.cgColor
|
|
337
|
+
viewAccountTypeNewAccountView.layer.shadowOpacity = 0.3
|
|
338
|
+
viewAccountTypeNewAccountView.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
339
|
+
viewAccountTypeNewAccountView.layer.shadowRadius = 4
|
|
340
|
+
viewAccountTypeNewAccountView.layer.cornerRadius = 8
|
|
341
|
+
viewAccountTypeNewAccountView.layer.cornerRadius = 8
|
|
342
|
+
|
|
343
|
+
viewAccountTypeNewAccountView.isHidden = true
|
|
344
|
+
|
|
345
|
+
// Generate and set the QR code image
|
|
346
|
+
qrImageView.image = generateQRCode(from: "CryptoQR")
|
|
347
|
+
|
|
348
|
+
setUpTermAndConditionsButton()
|
|
349
|
+
setUpTermAndConditionsForSingleSavedAccountButton()
|
|
350
|
+
|
|
351
|
+
settingsView.clipsToBounds = false
|
|
352
|
+
settingsView.layer.shadowColor = UIColor.black.cgColor
|
|
353
|
+
settingsView.layer.shadowOpacity = 0.3
|
|
354
|
+
settingsView.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
355
|
+
settingsView.layer.shadowRadius = 4
|
|
356
|
+
settingsView.layer.cornerRadius = 8
|
|
357
|
+
settingsView.layer.cornerRadius = 8
|
|
358
|
+
|
|
359
|
+
settingsView.isHidden = true
|
|
360
|
+
|
|
361
|
+
if UserStoreSingleton.shared.isLoggedIn == true {
|
|
362
|
+
btnSettings.isHidden = false
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
btnSettings.isHidden = true
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
//MARK: - View Wiil Appear
|
|
370
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
371
|
+
keyboardObserver.animateChanges({ [self] height in
|
|
372
|
+
let newConstant = CGFloat.maximum(height - self.view.safeAreaInsets.bottom + 8, 8)
|
|
373
|
+
buttonBottomConstraint.constant = newConstant
|
|
374
|
+
self.view.setNeedsLayout()
|
|
375
|
+
self.view.layoutIfNeeded()
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
viewTermAndConditionsSingleAccountView.isHidden = true
|
|
379
|
+
btnPayNowSingleAccountView.isHidden = true
|
|
380
|
+
viewSingleAccountViewHeight.constant = 68
|
|
381
|
+
|
|
382
|
+
viewNewBankAccount.isHidden = true
|
|
383
|
+
|
|
384
|
+
viewTxtFieldCVVSingleCard.isHidden = true
|
|
385
|
+
btnPayNowSingleCard.isHidden = true
|
|
386
|
+
viewSingleSavedCardHeight.constant = 60
|
|
387
|
+
|
|
388
|
+
self.viewCrypto.isHidden = true
|
|
389
|
+
|
|
390
|
+
if selectedPaymentMethod == "Card" {
|
|
391
|
+
if UserStoreSingleton.shared.isLoggedIn == true {
|
|
392
|
+
if UserStoreSingleton.shared.customerId == nil {
|
|
393
|
+
self.OTPView.isHidden = true
|
|
394
|
+
self.viewCardFields.isHidden = false
|
|
395
|
+
self.viewSingleSavedCard.isHidden = true
|
|
396
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
397
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
398
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
399
|
+
self.viewChangeCard.isHidden = true
|
|
400
|
+
self.viewUpdateCard.isHidden = true
|
|
401
|
+
self.viewAddNewCard.isHidden = true
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
self.getShowCardsApi()
|
|
405
|
+
self.viewCardFields.isHidden = true
|
|
406
|
+
self.viewSingleSavedCard.isHidden = false
|
|
407
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
408
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
409
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
410
|
+
self.viewChangeCard.isHidden = true
|
|
411
|
+
self.viewUpdateCard.isHidden = true
|
|
412
|
+
self.viewAddNewCard.isHidden = true
|
|
413
|
+
|
|
414
|
+
self.viewTxtFieldCVVSingleCard.isHidden = true
|
|
415
|
+
self.btnPayNowSingleCard.isHidden = true
|
|
416
|
+
self.viewSingleSavedCardHeight.constant = 60
|
|
417
|
+
self.btnNext.isHidden = true
|
|
418
|
+
self.btnNextHeight.constant = 0
|
|
419
|
+
self.btnNextTopCon.constant = 8
|
|
420
|
+
|
|
421
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
422
|
+
|
|
423
|
+
self.viewBankFields.isHidden = true
|
|
424
|
+
self.viewTermsAndConditions.isHidden = true
|
|
425
|
+
|
|
426
|
+
if isSelectForPay {
|
|
427
|
+
viewTxtFieldCVVSingleCard.isHidden = false
|
|
428
|
+
btnPayNowSingleCard.isHidden = false
|
|
429
|
+
viewSingleSavedCardHeight.constant = 220
|
|
430
|
+
btnNext.isHidden = true
|
|
431
|
+
btnNextHeight.constant = 0
|
|
432
|
+
btnNextTopCon.constant = 0
|
|
433
|
+
} else {
|
|
434
|
+
viewTxtFieldCVVSingleCard.isHidden = true
|
|
435
|
+
btnPayNowSingleCard.isHidden = true
|
|
436
|
+
viewSingleSavedCardHeight.constant = 60
|
|
437
|
+
btnNext.isHidden = true
|
|
438
|
+
btnNextHeight.constant = 0
|
|
439
|
+
btnNextTopCon.constant = 8
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
445
|
+
self.viewBankFields.isHidden = true
|
|
446
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
447
|
+
self.lblBtnShowSaveCard.text = "Show Saved Cards"
|
|
448
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
449
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
450
|
+
self.OTPView.isHidden = true
|
|
451
|
+
self.emailView.isHidden = true
|
|
452
|
+
self.viewCardFields.isHidden = false
|
|
453
|
+
self.viewSingleSavedCard.isHidden = true
|
|
454
|
+
self.viewChangeCard.isHidden = true
|
|
455
|
+
self.viewUpdateCard.isHidden = true
|
|
456
|
+
self.viewAddNewCard.isHidden = true
|
|
457
|
+
self.btnNext.isHidden = false
|
|
458
|
+
self.btnNextHeight.constant = 50
|
|
459
|
+
self.btnNextTopCon.constant = 20
|
|
460
|
+
self.viewTermsAndConditions.isHidden = true
|
|
461
|
+
self.viewCrypto.isHidden = true
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else if selectedPaymentMethod == "Bank" {
|
|
465
|
+
if UserStoreSingleton.shared.isLoggedIn == true {
|
|
466
|
+
|
|
467
|
+
if isFrom == "NewAccount" {
|
|
468
|
+
viewNewBankAccount.isHidden = false
|
|
469
|
+
} else {
|
|
470
|
+
viewSingleSavedAccount.isHidden = false
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
self.viewSingleSavedAccount.isHidden = false
|
|
474
|
+
self.viewBankFields.isHidden = true
|
|
475
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
476
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
477
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
478
|
+
self.OTPView.isHidden = true
|
|
479
|
+
self.emailView.isHidden = true
|
|
480
|
+
self.viewCardFields.isHidden = true
|
|
481
|
+
self.viewSingleSavedCard.isHidden = true
|
|
482
|
+
self.viewChangeCard.isHidden = true
|
|
483
|
+
self.viewUpdateCard.isHidden = true
|
|
484
|
+
self.viewAddNewCard.isHidden = true
|
|
485
|
+
self.btnNext.isHidden = true
|
|
486
|
+
self.btnNextHeight.constant = 0
|
|
487
|
+
self.btnNextTopCon.constant = 8
|
|
488
|
+
|
|
489
|
+
self.viewNewBankAccount.isHidden = true
|
|
490
|
+
self.viewCrypto.isHidden = true
|
|
491
|
+
|
|
492
|
+
self.viewTermsAndConditions.isHidden = true
|
|
493
|
+
|
|
494
|
+
self.viewChangedAccount.isHidden = true
|
|
495
|
+
|
|
496
|
+
if self.isSelectForPayBank {
|
|
497
|
+
self.viewTermAndConditionsSingleAccountView.isHidden = false
|
|
498
|
+
self.btnPayNowSingleAccountView.isHidden = false
|
|
499
|
+
self.viewSingleAccountViewHeight.constant = 170
|
|
500
|
+
} else {
|
|
501
|
+
self.viewTermAndConditionsSingleAccountView.isHidden = true
|
|
502
|
+
self.btnPayNowSingleAccountView.isHidden = true
|
|
503
|
+
self.viewSingleAccountViewHeight.constant = 68
|
|
504
|
+
self.btnNext.isHidden = true
|
|
505
|
+
self.btnNextHeight.constant = 0
|
|
506
|
+
self.btnNextTopCon.constant = 0
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
self.viewBankFields.isHidden = false
|
|
512
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
513
|
+
self.lblBtnShowSaveCard.text = "Use Saved Accounts"
|
|
514
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
515
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
516
|
+
self.OTPView.isHidden = true
|
|
517
|
+
self.emailView.isHidden = true
|
|
518
|
+
self.viewCardFields.isHidden = true
|
|
519
|
+
self.viewSingleSavedCard.isHidden = true
|
|
520
|
+
self.viewChangeCard.isHidden = true
|
|
521
|
+
self.viewUpdateCard.isHidden = true
|
|
522
|
+
self.viewAddNewCard.isHidden = true
|
|
523
|
+
self.btnNext.isHidden = false
|
|
524
|
+
self.btnNextHeight.constant = 50
|
|
525
|
+
self.btnNextTopCon.constant = 20
|
|
526
|
+
self.viewTermsAndConditions.isHidden = false
|
|
527
|
+
self.viewCrypto.isHidden = true
|
|
528
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
529
|
+
self.viewChangedAccount.isHidden = true
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
//CRYPTO
|
|
534
|
+
setOnChainSelected()
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
538
|
+
super.viewWillDisappear(animated)
|
|
539
|
+
keyboardObserver.invalidate()
|
|
540
|
+
resetTimer()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
func setUpTextFieldsDelegates() {
|
|
544
|
+
cardNumberTextField.textField.delegate = self
|
|
545
|
+
cardExpiryTextField.textField.delegate = self
|
|
546
|
+
cardCvvTextField.textField.delegate = self
|
|
547
|
+
cardNameTextField.textField.delegate = self
|
|
548
|
+
|
|
549
|
+
txtFieldEmail.delegate = self
|
|
550
|
+
|
|
551
|
+
txtFieldCVVSingleSavedCard.delegate = self
|
|
552
|
+
txtFieldExpireDateUpdateCardView.delegate = self
|
|
553
|
+
txtFieldCVVUpdateCardView.delegate = self
|
|
554
|
+
txtFieldNameOnCardUpdateCardView.delegate = self
|
|
555
|
+
|
|
556
|
+
txtFieldCardNumberNewCardView.delegate = self
|
|
557
|
+
txtFieldExpiryDateNewCardView.delegate = self
|
|
558
|
+
txtFieldCVVNewCardView.delegate = self
|
|
559
|
+
txtFieldNameOnCardNewCardView.delegate = self
|
|
560
|
+
|
|
561
|
+
txtFieldAccountName.delegate = self
|
|
562
|
+
txtFieldRoutingNumber.delegate = self
|
|
563
|
+
txtFieldAccountType.delegate = self
|
|
564
|
+
txtFieldAccountNumber.delegate = self
|
|
565
|
+
|
|
566
|
+
txtFieldAccountNameNewAccountView.delegate = self
|
|
567
|
+
txtFieldRoutingNumberNewAccountView.delegate = self
|
|
568
|
+
txtFieldAccountTypeNewAccountView.delegate = self
|
|
569
|
+
txtFieldAccountNumber.delegate = self
|
|
570
|
+
|
|
571
|
+
viewTextFieldCardNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
572
|
+
viewTxtFieldExpiryDate.layer.borderColor = UIColor.systemGray.cgColor
|
|
573
|
+
viewTxtFieldCVV.layer.borderColor = UIColor.systemGray.cgColor
|
|
574
|
+
viewTxtFieldNameOnCard.layer.borderColor = UIColor.systemGray.cgColor
|
|
575
|
+
viewTxtFieldEmail.layer.borderColor = UIColor.systemGray.cgColor
|
|
576
|
+
viewTxtFieldCVVSingleSavedCard.layer.borderColor = UIColor.systemGray.cgColor
|
|
577
|
+
//Update Card View
|
|
578
|
+
viewTxtFieldExpireDateUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
579
|
+
viewtxtFieldCVVUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
580
|
+
viewTxtFieldNameOnCardUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
581
|
+
//NEW Card View
|
|
582
|
+
viewtxtFieldCardNumberNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
583
|
+
viewtxtFieldExpiryDateNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
584
|
+
viewtxtFieldCVVNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
585
|
+
viewtxtFieldNameOnCardNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
586
|
+
//Bank View
|
|
587
|
+
viewtxtFieldAccountName.layer.borderColor = UIColor.systemGray.cgColor
|
|
588
|
+
viewtxtFieldRoutingNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
589
|
+
viewtxtFieldAccountType.layer.borderColor = UIColor.systemGray.cgColor
|
|
590
|
+
viewtxtFieldAccountNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
591
|
+
//New Bank Account View
|
|
592
|
+
viewtxtFieldAccountNameNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
593
|
+
viewtxtFieldRoutingNumberNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
594
|
+
viewtxtFieldAccountTypeNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
595
|
+
viewtxtFieldAccountNumberNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
//MARK: - Term & Conditions setup for normal bank fields view
|
|
599
|
+
func setUpTermAndConditionsButton() {
|
|
600
|
+
let string = "TERMS & CONDITIONS"
|
|
601
|
+
let attributedString = NSMutableAttributedString(string: string)
|
|
602
|
+
|
|
603
|
+
attributedString.addAttribute(
|
|
604
|
+
.font,
|
|
605
|
+
value: UIFont.systemFont(ofSize: 12, weight: .medium),
|
|
606
|
+
range: NSRange(location: 0, length: string.count)
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
// Assign the attributed string to the label
|
|
610
|
+
lblTermsAndConditions.attributedText = attributedString
|
|
611
|
+
lblTermsAndConditions.isUserInteractionEnabled = true
|
|
612
|
+
// Add tap gesture recognizer
|
|
613
|
+
let tap = UITapGestureRecognizer(target: self, action: #selector(aboutTerms))
|
|
614
|
+
lblTermsAndConditions.addGestureRecognizer(tap)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
@objc func aboutTerms(sender: UITapGestureRecognizer) {
|
|
618
|
+
guard let vc = UIStoryboard(name: "EasyPaySdk", bundle: Bundle.easyPayBundle).instantiateViewController(withIdentifier: "TermAndConditionsVC") as? TermAndConditionsVC else {
|
|
619
|
+
print("Error: Could not find TermAndConditionsVC in EasyPaySdk storyboard.")
|
|
620
|
+
return
|
|
621
|
+
}
|
|
622
|
+
vc.modalPresentationStyle = .overFullScreen
|
|
623
|
+
present(vc, animated: true, completion: nil)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
//MARK: - Term & Conditions setup for Signle saved bank account view
|
|
627
|
+
func setUpTermAndConditionsForSingleSavedAccountButton() {
|
|
628
|
+
let string = "TERMS & CONDITIONS"
|
|
629
|
+
let attributedString = NSMutableAttributedString(string: string)
|
|
630
|
+
|
|
631
|
+
attributedString.addAttribute(
|
|
632
|
+
.font,
|
|
633
|
+
value: UIFont.systemFont(ofSize: 12, weight: .medium),
|
|
634
|
+
range: NSRange(location: 0, length: string.count)
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
// Assign the attributed string to the label
|
|
638
|
+
lblTermsAndCondtionsSingleAccount.attributedText = attributedString
|
|
639
|
+
lblTermsAndCondtionsSingleAccount.isUserInteractionEnabled = true
|
|
640
|
+
// Add tap gesture recognizer
|
|
641
|
+
let tap = UITapGestureRecognizer(target: self, action: #selector(aboutTermsAndConditions))
|
|
642
|
+
lblTermsAndCondtionsSingleAccount.addGestureRecognizer(tap)
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
@objc func aboutTermsAndConditions(sender: UITapGestureRecognizer) {
|
|
646
|
+
guard let vc = UIStoryboard(name: "EasyPaySdk", bundle: Bundle.easyPayBundle).instantiateViewController(withIdentifier: "TermAndConditionsVC") as? TermAndConditionsVC else {
|
|
647
|
+
print("Error: Could not find TermAndConditionsVC in EasyPaySdk storyboard.")
|
|
648
|
+
return
|
|
649
|
+
}
|
|
650
|
+
vc.modalPresentationStyle = .overFullScreen
|
|
651
|
+
present(vc, animated: true, completion: nil)
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
func didPassTextBack(_ text: String) {
|
|
655
|
+
print("Received text: \(text)")
|
|
656
|
+
isFrom = text
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
|
660
|
+
guard keyPath == "contentSize" else {
|
|
661
|
+
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
|
|
662
|
+
return
|
|
663
|
+
}
|
|
664
|
+
// Update height for tblViewSavedCards
|
|
665
|
+
if let tableView = object as? UITableView, tableView == tblViewSavedCardsList {
|
|
666
|
+
tblViewSavedCardListHeight.constant = tblViewSavedCardsList.contentSize.height
|
|
667
|
+
}
|
|
668
|
+
// Update height for tblViewSavedAccounts
|
|
669
|
+
else if let tableView = object as? UITableView, tableView == tblViewSavedBankAccounts {
|
|
670
|
+
tblViewSavedBankAccountsHeight.constant = tblViewSavedBankAccounts.contentSize.height
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
UIView.animate(withDuration: 0.5) {
|
|
674
|
+
self.updateViewConstraints()
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
private func setupTextFields() {
|
|
679
|
+
let textFields = [txtFieldOTPText1, txtFieldOTPText2, txtFieldOTPText3, txtFieldOTPText4, txtFieldOTPText5, txtFieldOTPText6]
|
|
680
|
+
|
|
681
|
+
for textField in textFields {
|
|
682
|
+
textField?.delegate = self
|
|
683
|
+
textField?.textContentType = .oneTimeCode
|
|
684
|
+
textField?.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
func configureWith(request: Request, delegate: EasyPayViewControllerDelegate?) {
|
|
689
|
+
self.request = request
|
|
690
|
+
self.delegate = delegate
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
@objc func dismissKeyboard() {
|
|
694
|
+
self.view.endEditing(true)
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
private func startTimer() {
|
|
698
|
+
timeRemaining = 180 // 3 minutes
|
|
699
|
+
lblOtpTimer.text = formatTime(timeRemaining)
|
|
700
|
+
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
private func stopTimer() {
|
|
704
|
+
timer?.invalidate()
|
|
705
|
+
timer = nil
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
@objc private func updateTimer() {
|
|
709
|
+
if timeRemaining > 0 {
|
|
710
|
+
timeRemaining -= 1
|
|
711
|
+
lblOtpTimer.text = formatTime(timeRemaining)
|
|
712
|
+
} else {
|
|
713
|
+
stopTimer()
|
|
714
|
+
btnResendOTP.isHidden = false
|
|
715
|
+
imgEsclamationMark.isHidden = true
|
|
716
|
+
lblOtpTimer.isHidden = true
|
|
717
|
+
lblUntillResendOtp.isHidden = true
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
private func formatTime(_ seconds: Int) -> String {
|
|
722
|
+
let minutes = seconds / 60
|
|
723
|
+
let seconds = seconds % 60
|
|
724
|
+
return String(format: "%02d:%02d", minutes, seconds)
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
//MARK: - Crypto Functions
|
|
728
|
+
|
|
729
|
+
// Method to generate QR code from a string
|
|
730
|
+
private func generateQRCode(from string: String) -> UIImage? {
|
|
731
|
+
// Get data from the string
|
|
732
|
+
guard let data = string.data(using: .ascii) else { return nil }
|
|
733
|
+
// Get a QR CIFilter
|
|
734
|
+
guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
|
|
735
|
+
qrFilter.setValue(data, forKey: "inputMessage")
|
|
736
|
+
// Get the output image
|
|
737
|
+
guard let qrImage = qrFilter.outputImage else { return nil }
|
|
738
|
+
// Scale the image
|
|
739
|
+
let transform = CGAffineTransform(scaleX: 10, y: 10)
|
|
740
|
+
let scaledQrImage = qrImage.transformed(by: transform)
|
|
741
|
+
// Do some processing to get the UIImage
|
|
742
|
+
let context = CIContext()
|
|
743
|
+
guard let cgImage = context.createCGImage(scaledQrImage, from: scaledQrImage.extent) else { return nil }
|
|
744
|
+
|
|
745
|
+
return UIImage(cgImage: cgImage)
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
func startCryptoTimer() {
|
|
749
|
+
resetTimer()
|
|
750
|
+
|
|
751
|
+
lblTimerCrypto.text = formatTime(seconds: totalTimeInSeconds)
|
|
752
|
+
|
|
753
|
+
cryptoTimer = DispatchSource.makeTimerSource()
|
|
754
|
+
cryptoTimer?.schedule(deadline: .now(), repeating: 1.0)
|
|
755
|
+
cryptoTimer?.setEventHandler { [weak self] in
|
|
756
|
+
guard let self = self else { return }
|
|
757
|
+
|
|
758
|
+
DispatchQueue.main.async {
|
|
759
|
+
if self.totalTimeInSeconds > 0 {
|
|
760
|
+
self.totalTimeInSeconds -= 1
|
|
761
|
+
self.lblTimerCrypto.text = self.formatTime(seconds: self.totalTimeInSeconds)
|
|
762
|
+
} else {
|
|
763
|
+
self.resetTimer()
|
|
764
|
+
// Hide crypto view and show try again view when time is up
|
|
765
|
+
self.viewCryptoQRCode.isHidden = true
|
|
766
|
+
self.viewQrCodeHeight.constant = 225
|
|
767
|
+
self.viewCryptoHeight.constant = 225
|
|
768
|
+
self.viewCryptoTryAgain.isHidden = false
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
cryptoTimer?.resume()
|
|
774
|
+
isTimerRunning = true
|
|
775
|
+
|
|
776
|
+
// Start the 30-second interval timer
|
|
777
|
+
startCryptoInfoTimer()
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
func resetTimer() {
|
|
781
|
+
cryptoTimer?.cancel()
|
|
782
|
+
cryptoTimer = nil
|
|
783
|
+
totalTimeInSeconds = 300
|
|
784
|
+
isTimerRunning = false
|
|
785
|
+
|
|
786
|
+
// Stop the 30-second interval timer
|
|
787
|
+
stopCryptoInfoTimer()
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
func formatTime(seconds: Int) -> String {
|
|
791
|
+
let minutes = seconds / 60
|
|
792
|
+
let remainingSeconds = seconds % 60
|
|
793
|
+
return String(format: "%02d:%02d", minutes, remainingSeconds)
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
func startCryptoInfoTimer() {
|
|
797
|
+
// Invalidate any existing timer
|
|
798
|
+
cryptoInfoTimer?.invalidate()
|
|
799
|
+
// Schedule a new timer to call getCryptoPaymentInfoApi every 30 seconds
|
|
800
|
+
cryptoInfoTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in
|
|
801
|
+
guard let self = self else { return }
|
|
802
|
+
if let chargeId = self.chargeId {
|
|
803
|
+
self.getCryptoPaymentInfoApi(chargeId: chargeId)
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
func stopCryptoInfoTimer() {
|
|
809
|
+
cryptoInfoTimer?.invalidate()
|
|
810
|
+
cryptoInfoTimer = nil
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
@IBAction func actionBtnClose(_ sender: UIButton) {
|
|
814
|
+
UserStoreSingleton.shared.isLoggedIn = false
|
|
815
|
+
self.dismiss(animated: true)
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
@IBAction func actionBtnShowSavedCards(_ sender: UIButton) {
|
|
819
|
+
emailView.isHidden = false
|
|
820
|
+
OTPView.isHidden = true
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
@IBAction func actionBtnCloseEmailView(_ sender: UIButton) {
|
|
824
|
+
emailView.isHidden = true
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
@IBAction func actionBtnCloseOTPView(_ sender: UIButton) {
|
|
828
|
+
stopTimer()
|
|
829
|
+
OTPView.isHidden = true
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
@IBAction func actionBtnResendOTP(_ sender: UIButton) {
|
|
833
|
+
startTimer()
|
|
834
|
+
btnResendOTP.isHidden = true
|
|
835
|
+
imgEsclamationMark.isHidden = false
|
|
836
|
+
lblOtpTimer.isHidden = false
|
|
837
|
+
lblUntillResendOtp.isHidden = false
|
|
838
|
+
|
|
839
|
+
//Call email verification APi
|
|
840
|
+
emailVerificationApi()
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
@IBAction func actionBtnSelectSingleSavedCard(_ sender: UIButton) {
|
|
844
|
+
// Toggle the boolean property
|
|
845
|
+
isSelectForPay.toggle()
|
|
846
|
+
// Update the button image based on the state
|
|
847
|
+
let imageName = isSelectForPay ? "circle.inset.filled" : "circle"
|
|
848
|
+
sender.setImage(UIImage(systemName: imageName), for: .normal)
|
|
849
|
+
// Show or hide the view based on the state
|
|
850
|
+
if isSelectForPay {
|
|
851
|
+
viewTxtFieldCVVSingleCard.isHidden = false
|
|
852
|
+
btnPayNowSingleCard.isHidden = false
|
|
853
|
+
viewSingleSavedCardHeight.constant = 220
|
|
854
|
+
btnNext.isHidden = true
|
|
855
|
+
btnNextHeight.constant = 0
|
|
856
|
+
btnNextTopCon.constant = 0
|
|
857
|
+
if let firstCard = savedCards.first {
|
|
858
|
+
// Update the selectedCard to the firstCard or the card that is currently selected
|
|
859
|
+
selectedCard = firstCard
|
|
860
|
+
}
|
|
861
|
+
} else {
|
|
862
|
+
viewTxtFieldCVVSingleCard.isHidden = true
|
|
863
|
+
btnPayNowSingleCard.isHidden = true
|
|
864
|
+
viewSingleSavedCardHeight.constant = 60
|
|
865
|
+
btnNext.isHidden = true
|
|
866
|
+
btnNextHeight.constant = 0
|
|
867
|
+
btnNextTopCon.constant = 8
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
@IBAction func actionBtnChangeSavedCard(_ sender: UIButton) {
|
|
872
|
+
self.viewChangeCard.isHidden = false
|
|
873
|
+
self.viewCardFields.isHidden = true
|
|
874
|
+
self.viewSingleSavedCard.isHidden = true
|
|
875
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
876
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
877
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
878
|
+
self.viewUpdateCard.isHidden = true
|
|
879
|
+
self.viewAddNewCard.isHidden = true
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
@IBAction func actionBtnCloseChangedCardView(_ sender: UIButton) {
|
|
883
|
+
self.viewChangeCard.isHidden = true
|
|
884
|
+
self.viewSingleSavedCard.isHidden = false
|
|
885
|
+
self.viewCardFields.isHidden = true
|
|
886
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
887
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
888
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
889
|
+
self.viewUpdateCard.isHidden = true
|
|
890
|
+
self.viewAddNewCard.isHidden = true
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
@IBAction func actionBtnPayNowSingleSavedCard(_ sender: UIButton) {
|
|
894
|
+
// Check if billingInfoData is not nil or empty
|
|
895
|
+
if let billingInfoData = request.billingInfoData,
|
|
896
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
897
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
|
|
898
|
+
print("Billing Info Data: \(jsonDict)")
|
|
899
|
+
|
|
900
|
+
let cvvText = txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
901
|
+
|
|
902
|
+
// Show an alert if the CVV field is empty
|
|
903
|
+
if cvvText.isEmpty {
|
|
904
|
+
let alert = UIAlertController(title: "Missing CVV", message: "Please enter the CVV to proceed.", preferredStyle: .alert)
|
|
905
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
906
|
+
self.present(alert, animated: true, completion: nil)
|
|
907
|
+
return
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// Instantiate BillingInfoVC and pass the selected card data and CVV text
|
|
911
|
+
let billingInfoVC = UIStoryboard(name: "EasyPaySdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
912
|
+
|
|
913
|
+
billingInfoVC.isFrom = "SavedCards"
|
|
914
|
+
billingInfoVC.selectedCard = selectedCard // Passing the selected card data
|
|
915
|
+
billingInfoVC.cvvText = cvvText // Passing the CVV text
|
|
916
|
+
billingInfoVC.amount = Int(request.amount)
|
|
917
|
+
billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
|
|
918
|
+
|
|
919
|
+
// Pass the billing info data and auth token
|
|
920
|
+
if let billingInfoData = request.billingInfoData,
|
|
921
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
922
|
+
let jsonDict = json as? [String: Any] {
|
|
923
|
+
billingInfoVC.billingInfoData = jsonDict
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Navigate to BillingInfoVC
|
|
927
|
+
self.navigationController?.pushViewController(billingInfoVC, animated: true)
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
// If billingInfoData is nil or empty, set the button title to "Pay Now"
|
|
931
|
+
let cvvText = txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
932
|
+
|
|
933
|
+
// Show an alert if the CVV field is empty
|
|
934
|
+
if cvvText.isEmpty {
|
|
935
|
+
let alert = UIAlertController(title: "Missing CVV", message: "Please enter the CVV to proceed.", preferredStyle: .alert)
|
|
936
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
937
|
+
self.present(alert, animated: true, completion: nil)
|
|
938
|
+
return
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
paymentIntentFromShowSavedCardApi()
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
@IBAction func actionBtnSelectUpdateCardView(_ sender: UIButton) {
|
|
947
|
+
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
@IBAction func actionBtnUpdateCard(_ sender: UIButton) {
|
|
951
|
+
// Check if a card ID is selected
|
|
952
|
+
guard let cardID = selectedCardID else {
|
|
953
|
+
let alert = UIAlertController(title: "No Card Selected", message: "Please select a card to update.", preferredStyle: .alert)
|
|
954
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
955
|
+
self.present(alert, animated: true, completion: nil)
|
|
956
|
+
return
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Call the updateCardApi with the selected card's ID
|
|
960
|
+
updateCardApi(cardID: cardID)
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
@IBAction func actionBtnCloseUpdateCardView(_ sender: UIButton) {
|
|
964
|
+
self.viewChangeCard.isHidden = false
|
|
965
|
+
self.viewSingleSavedCard.isHidden = true
|
|
966
|
+
self.viewCardFields.isHidden = true
|
|
967
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
968
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
969
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
970
|
+
self.viewUpdateCard.isHidden = true
|
|
971
|
+
self.viewAddNewCard.isHidden = true
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
@IBAction func actionBtnCloseNewCardView(_ sender: UIButton) {
|
|
975
|
+
self.viewChangeCard.isHidden = false
|
|
976
|
+
self.viewSingleSavedCard.isHidden = true
|
|
977
|
+
self.viewCardFields.isHidden = true
|
|
978
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
979
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
980
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
981
|
+
self.viewUpdateCard.isHidden = true
|
|
982
|
+
self.viewAddNewCard.isHidden = true
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
@IBAction func actionBtnPayNowNewCardView(_ sender: UIButton) {
|
|
986
|
+
if UserStoreSingleton.shared.isLoggedIn == true {
|
|
987
|
+
//if billing info is availbale
|
|
988
|
+
if let billingInfoData = request.billingInfoData,
|
|
989
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
990
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
|
|
991
|
+
print("Billing Info Data: \(jsonDict)")
|
|
992
|
+
|
|
993
|
+
// Retrieve and trim text field values (removing leading and trailing whitespace)
|
|
994
|
+
let cardNumber = txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
995
|
+
let expiryDate = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
996
|
+
let cvv = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
997
|
+
let nameOnCard = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
998
|
+
|
|
999
|
+
// Check if any field is empty
|
|
1000
|
+
if cardNumber.isEmpty || expiryDate.isEmpty || cvv.isEmpty || nameOnCard.isEmpty {
|
|
1001
|
+
let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
|
|
1002
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
1003
|
+
self.present(alert, animated: true, completion: nil)
|
|
1004
|
+
return
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Validate expiry date format
|
|
1008
|
+
let expiryDateFormat = "MM/yyyy"
|
|
1009
|
+
let dateFormatter = DateFormatter()
|
|
1010
|
+
dateFormatter.dateFormat = expiryDateFormat
|
|
1011
|
+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
1012
|
+
|
|
1013
|
+
// Split the expiry date and validate its format
|
|
1014
|
+
let exp = expiryDate.split(separator: "/")
|
|
1015
|
+
if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
|
|
1016
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
1017
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
1018
|
+
self.present(alert, animated: true, completion: nil)
|
|
1019
|
+
return
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Check if the expiry date is valid
|
|
1023
|
+
if let expiryDateObj = dateFormatter.date(from: expiryDate) {
|
|
1024
|
+
// Check if the expiry date is in the past
|
|
1025
|
+
let currentDate = Date()
|
|
1026
|
+
let calendar = Calendar.current
|
|
1027
|
+
let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
|
|
1028
|
+
if expiryDateObj < currentMonthYear! {
|
|
1029
|
+
let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
|
|
1030
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
1031
|
+
self.present(alert, animated: true, completion: nil)
|
|
1032
|
+
return
|
|
1033
|
+
}
|
|
1034
|
+
} else {
|
|
1035
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
1036
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
1037
|
+
self.present(alert, animated: true, completion: nil)
|
|
1038
|
+
return
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Instantiate BillingInfoVC and pass the card details
|
|
1042
|
+
let billingInfoVC = UIStoryboard(name: "EasyPaySdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1043
|
+
|
|
1044
|
+
// Pass the card details
|
|
1045
|
+
billingInfoVC.cardNumber = cardNumber
|
|
1046
|
+
billingInfoVC.expiryDate = expiryDate
|
|
1047
|
+
billingInfoVC.cvv = cvv
|
|
1048
|
+
billingInfoVC.nameOnCard = nameOnCard
|
|
1049
|
+
billingInfoVC.isSavedNewCard = isSavedNewCardForFuture
|
|
1050
|
+
|
|
1051
|
+
billingInfoVC.isFrom = "AddNewCard"
|
|
1052
|
+
billingInfoVC.amount = Int(request.amount)
|
|
1053
|
+
billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
|
|
1054
|
+
|
|
1055
|
+
// Pass the billing info data and auth token
|
|
1056
|
+
if let billingInfoData = request.billingInfoData,
|
|
1057
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
1058
|
+
let jsonDict = json as? [String: Any] {
|
|
1059
|
+
billingInfoVC.billingInfoData = jsonDict
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// Navigate to BillingInfoVC
|
|
1063
|
+
self.navigationController?.pushViewController(billingInfoVC, animated: true)
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
paymentIntentFromAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
@IBAction func actionBtnSaveCardForFutureNewCardView(_ sender: UIButton) {
|
|
1072
|
+
isSavedNewCardForFuture.toggle()
|
|
1073
|
+
// Change the image based on the state
|
|
1074
|
+
let imageName = isSavedNewCardForFuture ? "checkmark.square.fill" : "square"
|
|
1075
|
+
btnSavedCardForFutureNewCardView.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
@IBAction func actionBtnSaveCardForFuture(_ sender: UIButton) {
|
|
1079
|
+
isSavedForFuture.toggle()
|
|
1080
|
+
// Change the image based on the state
|
|
1081
|
+
let imageName = isSavedForFuture ? "checkmark.square.fill" : "square"
|
|
1082
|
+
btnCheckBoxSavedCard.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// MARK: - Action Button Next
|
|
1086
|
+
@IBAction func actionBtnNext(_ sender: UIButton) {
|
|
1087
|
+
// Check if billing info data exists and is valid JSON
|
|
1088
|
+
if let billingInfoData = request.billingInfoData {
|
|
1089
|
+
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
|
|
1090
|
+
// Perform JSON parsing in a background thread
|
|
1091
|
+
guard let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
1092
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty else {
|
|
1093
|
+
return
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
DispatchQueue.main.async {
|
|
1097
|
+
// Ensure UI updates happen on the main thread
|
|
1098
|
+
guard let self = self else { return }
|
|
1099
|
+
|
|
1100
|
+
if self.selectedPaymentMethod == "Card" {
|
|
1101
|
+
// Validate card fields
|
|
1102
|
+
if self.cardNumberTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1103
|
+
self.showAlert(title: "Missing Information", message: "Card Number is required.")
|
|
1104
|
+
} else if self.cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1105
|
+
self.showAlert(title: "Missing Information", message: "Card Expiry Date is required.")
|
|
1106
|
+
} else if self.cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1107
|
+
self.showAlert(title: "Missing Information", message: "Card CVV Number is required.")
|
|
1108
|
+
} else if self.cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1109
|
+
self.showAlert(title: "Missing Information", message: "Card Name is required.")
|
|
1110
|
+
} else {
|
|
1111
|
+
// Proceed to BillingInfoVC
|
|
1112
|
+
let vc = EasyPaySdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1113
|
+
vc.billingInfoData = jsonDict
|
|
1114
|
+
vc.cardNumber = self.cardNumberTextField.text
|
|
1115
|
+
vc.expiryDate = self.cardExpiryTextField.text
|
|
1116
|
+
vc.cvv = self.cardCvvTextField.text
|
|
1117
|
+
vc.nameOnCard = self.cardNameTextField.text
|
|
1118
|
+
vc.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1119
|
+
vc.isSavedForFuture = self.isSavedForFuture
|
|
1120
|
+
self.navigationController?.pushViewController(vc, animated: true)
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
else if self.selectedPaymentMethod == "Bank" {
|
|
1124
|
+
// Bank Case
|
|
1125
|
+
if self.txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1126
|
+
self.showAlert(title: "Missing Information", message: "Bank account name is required.")
|
|
1127
|
+
} else if self.txtFieldRoutingNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1128
|
+
self.showAlert(title: "Missing Information", message: "Routing number is required.")
|
|
1129
|
+
} else if self.txtFieldAccountType.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1130
|
+
self.showAlert(title: "Missing Information", message: "Bank account type is required.")
|
|
1131
|
+
} else if self.txtFieldAccountNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1132
|
+
self.showAlert(title: "Missing Information", message: "Bank account number is required.")
|
|
1133
|
+
}
|
|
1134
|
+
else if !self.agreeTermsAndCondtition {
|
|
1135
|
+
self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
|
|
1136
|
+
return
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
// Proceed to BillingInfoVC
|
|
1140
|
+
let vc = EasyPaySdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1141
|
+
vc.accountName = self.txtFieldAccountName.text
|
|
1142
|
+
vc.routingNumber = self.txtFieldRoutingNumber.text
|
|
1143
|
+
vc.accountType = self.txtFieldAccountType.text
|
|
1144
|
+
vc.accountNumber = self.txtFieldAccountNumber.text
|
|
1145
|
+
vc.billingInfoData = jsonDict
|
|
1146
|
+
vc.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1147
|
+
vc.isSavedForFuture = self.isSavedForFuture
|
|
1148
|
+
vc.isFrom = "NormalBankPayWithoutSave"
|
|
1149
|
+
self.navigationController?.pushViewController(vc, animated: true)
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
} else {
|
|
1155
|
+
// Billing info is nil or empty
|
|
1156
|
+
if selectedPaymentMethod == "Card" {
|
|
1157
|
+
// Card Case
|
|
1158
|
+
if cardNumberTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1159
|
+
showAlert(title: "Missing Information", message: "Card Number is required.")
|
|
1160
|
+
} else if cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1161
|
+
showAlert(title: "Missing Information", message: "Card Expiry Date is required.")
|
|
1162
|
+
} else if cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1163
|
+
showAlert(title: "Missing Information", message: "Card CVV Number is required.")
|
|
1164
|
+
} else if cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
1165
|
+
showAlert(title: "Missing Information", message: "Card Name is required.")
|
|
1166
|
+
} else {
|
|
1167
|
+
// Navigate to EmailVerificationVC if isSavedForFuture is true, else call paymentIntentApi
|
|
1168
|
+
if isSavedForFuture {
|
|
1169
|
+
navigateCardDataToEmailVerificationVC()
|
|
1170
|
+
} else {
|
|
1171
|
+
paymentIntentApi()
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
else if selectedPaymentMethod == "Bank" {
|
|
1176
|
+
// Bank Case
|
|
1177
|
+
if txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1178
|
+
showAlert(title: "Missing Information", message: "Bank account name is required.")
|
|
1179
|
+
} else if txtFieldRoutingNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1180
|
+
showAlert(title: "Missing Information", message: "Routing number is required.")
|
|
1181
|
+
} else if txtFieldAccountType.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1182
|
+
showAlert(title: "Missing Information", message: "Bank account type is required.")
|
|
1183
|
+
} else if txtFieldAccountNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
|
|
1184
|
+
showAlert(title: "Missing Information", message: "Bank account number is required.")
|
|
1185
|
+
}
|
|
1186
|
+
else if !agreeTermsAndCondtition {
|
|
1187
|
+
showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
|
|
1188
|
+
return
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
if isSavedForFuture {
|
|
1192
|
+
navigateBankDataToEmailVerificationVC()
|
|
1193
|
+
} else {
|
|
1194
|
+
accountChargeApi()
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// Function to navigate to EmailVerificationVC
|
|
1202
|
+
func navigateCardDataToEmailVerificationVC() {
|
|
1203
|
+
if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
|
|
1204
|
+
emailVerificationVC.cardNumber = self.cardNumberTextField.text
|
|
1205
|
+
emailVerificationVC.expiryDate = self.cardExpiryTextField.text
|
|
1206
|
+
emailVerificationVC.cvv = self.cardCvvTextField.text
|
|
1207
|
+
emailVerificationVC.nameOnCard = self.cardNameTextField.text
|
|
1208
|
+
emailVerificationVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1209
|
+
emailVerificationVC.isSavedForFuture = isSavedForFuture
|
|
1210
|
+
emailVerificationVC.easyPayDelegate = self.easyPayDelegate // Pass delegate if needed
|
|
1211
|
+
self.navigationController?.pushViewController(emailVerificationVC, animated: true)
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
func navigateBankDataToEmailVerificationVC() {
|
|
1216
|
+
if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
|
|
1217
|
+
emailVerificationVC.accountName = txtFieldAccountName.text
|
|
1218
|
+
emailVerificationVC.routingNumber = txtFieldRoutingNumber.text
|
|
1219
|
+
emailVerificationVC.accountType = txtFieldAccountType.text
|
|
1220
|
+
emailVerificationVC.accountNumber = txtFieldAccountNumber.text
|
|
1221
|
+
emailVerificationVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1222
|
+
emailVerificationVC.isSavedForFuture = isSavedForFuture
|
|
1223
|
+
emailVerificationVC.easyPayDelegate = self.easyPayDelegate // Pass delegate if needed
|
|
1224
|
+
self.navigationController?.pushViewController(emailVerificationVC, animated: true)
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
@IBAction func actionBtnSettings(_ sender: UIButton) {
|
|
1229
|
+
settingsView.isHidden = false
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
@IBAction func actionBtnLogout(_ sender: UIButton) {
|
|
1233
|
+
UserStoreSingleton.shared.clearUserData()
|
|
1234
|
+
UserStoreSingleton.shared.isLoggedIn = false
|
|
1235
|
+
settingsView.isHidden = true
|
|
1236
|
+
btnSettings.isHidden = true
|
|
1237
|
+
txtFieldEmail.text = ""
|
|
1238
|
+
txtFieldOTPText1.text = ""
|
|
1239
|
+
txtFieldOTPText2.text = ""
|
|
1240
|
+
txtFieldOTPText3.text = ""
|
|
1241
|
+
txtFieldOTPText4.text = ""
|
|
1242
|
+
txtFieldOTPText5.text = ""
|
|
1243
|
+
txtFieldOTPText6.text = ""
|
|
1244
|
+
|
|
1245
|
+
if selectedPaymentMethod == "Card" {
|
|
1246
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
1247
|
+
self.viewBankFields.isHidden = true
|
|
1248
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
1249
|
+
self.lblBtnShowSaveCard.text = "Show Saved Cards"
|
|
1250
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
1251
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
1252
|
+
self.OTPView.isHidden = true
|
|
1253
|
+
self.emailView.isHidden = true
|
|
1254
|
+
self.viewCardFields.isHidden = false
|
|
1255
|
+
self.viewSingleSavedCard.isHidden = true
|
|
1256
|
+
self.viewChangeCard.isHidden = true
|
|
1257
|
+
self.viewUpdateCard.isHidden = true
|
|
1258
|
+
self.viewAddNewCard.isHidden = true
|
|
1259
|
+
self.btnNext.isHidden = false
|
|
1260
|
+
self.btnNextHeight.constant = 50
|
|
1261
|
+
self.btnNextTopCon.constant = 20
|
|
1262
|
+
self.viewTermsAndConditions.isHidden = true
|
|
1263
|
+
self.viewCrypto.isHidden = true
|
|
1264
|
+
}
|
|
1265
|
+
else if selectedPaymentMethod == "Bank" {
|
|
1266
|
+
self.viewBankFields.isHidden = false
|
|
1267
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
1268
|
+
self.lblBtnShowSaveCard.text = "Use Saved Accounts"
|
|
1269
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
1270
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
1271
|
+
self.OTPView.isHidden = true
|
|
1272
|
+
self.emailView.isHidden = true
|
|
1273
|
+
self.viewCardFields.isHidden = true
|
|
1274
|
+
self.viewSingleSavedCard.isHidden = true
|
|
1275
|
+
self.viewChangeCard.isHidden = true
|
|
1276
|
+
self.viewUpdateCard.isHidden = true
|
|
1277
|
+
self.viewAddNewCard.isHidden = true
|
|
1278
|
+
self.btnNext.isHidden = false
|
|
1279
|
+
self.btnNextHeight.constant = 50
|
|
1280
|
+
self.btnNextTopCon.constant = 20
|
|
1281
|
+
self.viewTermsAndConditions.isHidden = false
|
|
1282
|
+
self.viewCrypto.isHidden = true
|
|
1283
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
1284
|
+
self.viewChangedAccount.isHidden = true
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
@IBAction func actionBtnCloseSettingView(_ sender: UIButton) {
|
|
1289
|
+
settingsView.isHidden = true
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
//MARK: - Bank View Buttons Actions
|
|
1293
|
+
@IBAction func actionBtnSelectAccountType(_ sender: UIButton) {
|
|
1294
|
+
UIView.animate(withDuration: 0.3) {
|
|
1295
|
+
self.viewAccountType.isHidden.toggle()
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
@IBAction func actionBtnSaveAccountForFuture(_ sender: UIButton) {
|
|
1300
|
+
isSavedForFuture.toggle()
|
|
1301
|
+
// Change the image based on the state
|
|
1302
|
+
let imageName = isSavedForFuture ? "checkmark.square.fill" : "square"
|
|
1303
|
+
btnCheckSavedAccountForFuture.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
@IBAction func actionBtnCheckAgreeTermsConditions(_ sender: UIButton) {
|
|
1307
|
+
agreeTermsAndCondtition.toggle()
|
|
1308
|
+
// Change the image based on the state
|
|
1309
|
+
let imageName = agreeTermsAndCondtition ? "checkmark.square.fill" : "square"
|
|
1310
|
+
btnAgreeTermsConditions.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
@IBAction func actionBtnSelectSingleAccountView(_ sender: UIButton) {
|
|
1314
|
+
// Toggle the boolean property
|
|
1315
|
+
isSelectForPayBank.toggle()
|
|
1316
|
+
// Update the button image based on the state
|
|
1317
|
+
let imageName = isSelectForPayBank ? "circle.inset.filled" : "circle"
|
|
1318
|
+
sender.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1319
|
+
// Show or hide the view based on the state
|
|
1320
|
+
if isSelectForPayBank {
|
|
1321
|
+
viewTermAndConditionsSingleAccountView.isHidden = false
|
|
1322
|
+
btnPayNowSingleAccountView.isHidden = false
|
|
1323
|
+
viewSingleAccountViewHeight.constant = 170
|
|
1324
|
+
} else {
|
|
1325
|
+
viewTermAndConditionsSingleAccountView.isHidden = true
|
|
1326
|
+
btnPayNowSingleAccountView.isHidden = true
|
|
1327
|
+
viewSingleAccountViewHeight.constant = 68
|
|
1328
|
+
btnNext.isHidden = true
|
|
1329
|
+
btnNextHeight.constant = 0
|
|
1330
|
+
btnNextTopCon.constant = 0
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
@IBAction func actionBtnChangeSingleAccountView(_ sender: UIButton) {
|
|
1335
|
+
self.viewChangedAccount.isHidden = false
|
|
1336
|
+
self.viewBankFields.isHidden = true
|
|
1337
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
@IBAction func actionBtnAgreeTermsConditionsSingleAccountView(_ sender: UIButton) {
|
|
1341
|
+
agreeTermsAndCondtition.toggle()
|
|
1342
|
+
// Change the image based on the state
|
|
1343
|
+
let imageName = agreeTermsAndCondtition ? "checkmark.square.fill" : "square"
|
|
1344
|
+
btnCheckAgreeTermsAndConditionsSingleAccount.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
@IBAction func actionBtnPayNowSingleAccountView(_ sender: UIButton) {
|
|
1348
|
+
// Check if billingInfoData is not nil or empty
|
|
1349
|
+
if let billingInfoData = request.billingInfoData,
|
|
1350
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
1351
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
|
|
1352
|
+
|
|
1353
|
+
// Check if the terms and conditions are agreed
|
|
1354
|
+
if !agreeTermsAndCondtition {
|
|
1355
|
+
showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
|
|
1356
|
+
return
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// Proceed with the Pay Now action
|
|
1360
|
+
let vc = EasyPaySdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1361
|
+
// Pass the customer_id and account_id to BillingInfoVC
|
|
1362
|
+
vc.customerID = selectedbankAccounts?.customer_id
|
|
1363
|
+
vc.accountID = selectedbankAccounts?.account_id
|
|
1364
|
+
vc.billingInfoData = jsonDict
|
|
1365
|
+
vc.isFrom = "SavedBank"
|
|
1366
|
+
vc.selectedPaymentMethod = "Bank"
|
|
1367
|
+
self.navigationController?.pushViewController(vc, animated: true)
|
|
1368
|
+
}
|
|
1369
|
+
else {
|
|
1370
|
+
//If Billing info is nil or empty
|
|
1371
|
+
if !agreeTermsAndCondtition {
|
|
1372
|
+
showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
|
|
1373
|
+
return
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
accountChargeSavedBankAccountApi()
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
@IBAction func actionBtnCloseChangeAccountView(_ sender: UIButton) {
|
|
1381
|
+
viewChangedAccount.isHidden = true
|
|
1382
|
+
viewSingleSavedAccount.isHidden = false
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
@IBAction func actionBtnSaveAccountNewAccountView(_ sender: UIButton) {
|
|
1386
|
+
isSavedNewAccount.toggle()
|
|
1387
|
+
// Change the image based on the state
|
|
1388
|
+
let imageName = isSavedNewAccount ? "checkmark.square.fill" : "square"
|
|
1389
|
+
btnSavedNewAccountForFuture.setImage(UIImage(systemName: imageName), for: .normal)
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
@IBAction func actionBtnAccontTypeNewAccountView(_ sender: UIButton) {
|
|
1393
|
+
UIView.animate(withDuration: 0.3) {
|
|
1394
|
+
self.viewAccountTypeNewAccountView.isHidden.toggle()
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
@IBAction func actionBtnPayNowNewAccountView(_ sender: UIButton) {
|
|
1399
|
+
// Check if billingInfoData is not nil or empty
|
|
1400
|
+
if let billingInfoData = request.billingInfoData,
|
|
1401
|
+
let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
|
|
1402
|
+
let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
|
|
1403
|
+
print("Billing Info Data: \(jsonDict)")
|
|
1404
|
+
|
|
1405
|
+
// Retrieve and trim text field values (removing leading and trailing whitespace)
|
|
1406
|
+
let accountName = txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
1407
|
+
let routingNumber = txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
1408
|
+
let accountType = txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
1409
|
+
let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
1410
|
+
|
|
1411
|
+
// Check if any field is empty
|
|
1412
|
+
if accountName.isEmpty || routingNumber.isEmpty || accountType.isEmpty || accountNumber.isEmpty {
|
|
1413
|
+
let alert = UIAlertController(title: "Missing Information", message: "Please fill in all bank details.", preferredStyle: .alert)
|
|
1414
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
1415
|
+
self.present(alert, animated: true, completion: nil)
|
|
1416
|
+
return
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
// Determine the vc.isFrom value based on isSavedNewAccount
|
|
1420
|
+
let isSavedNewAccount = isSavedNewAccount
|
|
1421
|
+
let isFromValue = isSavedNewAccount ? "AddNewAccountWithSave" : "AddNewAccountWithoutSave"
|
|
1422
|
+
|
|
1423
|
+
// Proceed with the Pay Now action
|
|
1424
|
+
let vc = EasyPaySdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1425
|
+
vc.accountName = accountName
|
|
1426
|
+
vc.routingNumber = routingNumber
|
|
1427
|
+
vc.accountType = accountType
|
|
1428
|
+
vc.accountNumber = accountNumber
|
|
1429
|
+
vc.billingInfoData = jsonDict
|
|
1430
|
+
vc.selectedPaymentMethod = "Bank"
|
|
1431
|
+
vc.isFrom = isFromValue
|
|
1432
|
+
vc.isSavedNewAccount = isSavedNewAccount
|
|
1433
|
+
vc.delegate = self
|
|
1434
|
+
self.navigationController?.pushViewController(vc, animated: true)
|
|
1435
|
+
}
|
|
1436
|
+
else {
|
|
1437
|
+
//If Billing info is nil or empty
|
|
1438
|
+
let isSavedNewAccount = isSavedNewAccount
|
|
1439
|
+
// If Billing info is nil or empty, call the appropriate API
|
|
1440
|
+
if isSavedNewAccount {
|
|
1441
|
+
// Call accountChargeApi if the account is saved
|
|
1442
|
+
accountChargeApi(customerId: UserStoreSingleton.shared.customerId)
|
|
1443
|
+
} else {
|
|
1444
|
+
// Call accountChargeAddNewAccountApi if the account is new
|
|
1445
|
+
accountChargeAddNewAccountApi()
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
@IBAction func actionBtnCloseNewAccountView(_ sender: UIButton) {
|
|
1451
|
+
self.viewNewBankAccount.isHidden = true
|
|
1452
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
1453
|
+
self.viewBankFields.isHidden = true
|
|
1454
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
1455
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
1456
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
1457
|
+
self.OTPView.isHidden = true
|
|
1458
|
+
self.emailView.isHidden = true
|
|
1459
|
+
self.viewCardFields.isHidden = true
|
|
1460
|
+
self.viewSingleSavedCard.isHidden = true
|
|
1461
|
+
self.viewChangeCard.isHidden = true
|
|
1462
|
+
self.viewUpdateCard.isHidden = true
|
|
1463
|
+
self.viewAddNewCard.isHidden = true
|
|
1464
|
+
self.btnNext.isHidden = true
|
|
1465
|
+
self.btnNextHeight.constant = 0
|
|
1466
|
+
self.btnNextTopCon.constant = 8
|
|
1467
|
+
self.viewChangedAccount.isHidden = false
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
//MARK: - Crypto View Buttons Actions
|
|
1471
|
+
@IBAction func actionBtnTryAgain(_ sender: UIButton) {
|
|
1472
|
+
// Call the crypto charge API again
|
|
1473
|
+
cryptoChargeApi()
|
|
1474
|
+
// Reset the view and timer
|
|
1475
|
+
DispatchQueue.main.async {
|
|
1476
|
+
self.viewCryptoQRCode.isHidden = false
|
|
1477
|
+
self.viewCryptoTryAgain.isHidden = true
|
|
1478
|
+
self.viewQrCodeHeight.constant = 440
|
|
1479
|
+
self.viewCryptoHeight.constant = 440
|
|
1480
|
+
self.resetTimer()
|
|
1481
|
+
self.startCryptoTimer()
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
func setOnChainSelected() {
|
|
1486
|
+
// Set the selected state for OnChain button
|
|
1487
|
+
btnOnChain.backgroundColor = .systemBlue
|
|
1488
|
+
btnOnChain.setTitleColor(.white, for: .normal)
|
|
1489
|
+
// Reset the state for Lightning button
|
|
1490
|
+
btnLightning.backgroundColor = .clear
|
|
1491
|
+
btnLightning.setTitleColor(.systemBlue, for: .normal)
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
@IBAction func actionBtnOnChain(_ sender: UIButton) {
|
|
1495
|
+
// Set the selected state for OnChain button
|
|
1496
|
+
setOnChainSelected()
|
|
1497
|
+
// Generate QR code for Chain Invoice Address
|
|
1498
|
+
if let address = chainInvoiceAddress {
|
|
1499
|
+
qrImageView.image = generateQRCode(from: address)
|
|
1500
|
+
lblBTCAddress.text = "BTC Address: \(address)" // Update lblBTCAddress with the Chain Invoice Address
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
@IBAction func actionBtnLightning(_ sender: UIButton) {
|
|
1505
|
+
// Set the selected state for Lightning button
|
|
1506
|
+
btnLightning.backgroundColor = .systemBlue
|
|
1507
|
+
btnLightning.setTitleColor(.white, for: .normal)
|
|
1508
|
+
// Reset the state for OnChain button
|
|
1509
|
+
btnOnChain.backgroundColor = .clear
|
|
1510
|
+
btnOnChain.setTitleColor(.systemBlue, for: .normal)
|
|
1511
|
+
|
|
1512
|
+
// Generate QR code for Lightning URI
|
|
1513
|
+
if let uri = lightningURI {
|
|
1514
|
+
qrImageView.image = generateQRCode(from: uri)
|
|
1515
|
+
lblBTCAddress.text = "BTC Address: \(uri)" // Update lblBTCAddress with the Lightning URI
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
@IBAction func actionBtnCopyBTCAddress(_ sender: UIButton) {
|
|
1520
|
+
// Check if there is text to copy
|
|
1521
|
+
guard let btcAddressText = lblBTCAddress.text, !btcAddressText.isEmpty else {
|
|
1522
|
+
print("No address to copy")
|
|
1523
|
+
return
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// Extract the actual BTC address from the label text
|
|
1527
|
+
let components = btcAddressText.components(separatedBy: "BTC Address: ")
|
|
1528
|
+
if components.count > 1 {
|
|
1529
|
+
let btcAddress = components[1]
|
|
1530
|
+
|
|
1531
|
+
// Copy the address to the clipboard
|
|
1532
|
+
UIPasteboard.general.string = btcAddress
|
|
1533
|
+
|
|
1534
|
+
// Print success message to the console
|
|
1535
|
+
print("Address copied to clipboard successfully: \(btcAddress)")
|
|
1536
|
+
|
|
1537
|
+
// Optionally, show a toast message to the user
|
|
1538
|
+
showToast(message: "BTC Address copied to clipboard")
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
//MARK: - Send OTP Email Verification Api
|
|
1543
|
+
func emailVerificationApi() {
|
|
1544
|
+
showLoadingIndicator()
|
|
1545
|
+
|
|
1546
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
1547
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.emailVerification.path()
|
|
1548
|
+
|
|
1549
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1550
|
+
print("Invalid URL")
|
|
1551
|
+
hideLoadingIndicator()
|
|
1552
|
+
return
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
var request = URLRequest(url: serviceURL)
|
|
1556
|
+
request.httpMethod = "POST"
|
|
1557
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1558
|
+
|
|
1559
|
+
// Use the clientToken from your singleton
|
|
1560
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1561
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1562
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1563
|
+
|
|
1564
|
+
// Define the parameters for the request
|
|
1565
|
+
let params: [String: Any] = [
|
|
1566
|
+
"card_search_value": txtFieldEmail.text ?? "",
|
|
1567
|
+
"card_search_key": "email"
|
|
1568
|
+
]
|
|
1569
|
+
|
|
1570
|
+
do {
|
|
1571
|
+
// Convert the dictionary to JSON
|
|
1572
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
1573
|
+
request.httpBody = jsonData
|
|
1574
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1575
|
+
print("JSON Payload: \(jsonString)")
|
|
1576
|
+
}
|
|
1577
|
+
} catch let error {
|
|
1578
|
+
print("Error creating JSON data: \(error)")
|
|
1579
|
+
hideLoadingIndicator()
|
|
1580
|
+
return
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
let session = URLSession.shared
|
|
1584
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
1585
|
+
|
|
1586
|
+
DispatchQueue.main.async {
|
|
1587
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
if let error = error {
|
|
1591
|
+
print("Error: \(error.localizedDescription)")
|
|
1592
|
+
return
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
1596
|
+
print("Invalid response")
|
|
1597
|
+
return
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
1601
|
+
if let data = serviceData {
|
|
1602
|
+
do {
|
|
1603
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
1604
|
+
print("Response Data: \(responseObject)")
|
|
1605
|
+
DispatchQueue.main.async {
|
|
1606
|
+
// Handle successful response
|
|
1607
|
+
}
|
|
1608
|
+
} else {
|
|
1609
|
+
print("Invalid JSON format")
|
|
1610
|
+
}
|
|
1611
|
+
} catch let jsonError {
|
|
1612
|
+
print("Error parsing JSON: \(jsonError)")
|
|
1613
|
+
}
|
|
1614
|
+
} else {
|
|
1615
|
+
print("No data received")
|
|
1616
|
+
}
|
|
1617
|
+
} else {
|
|
1618
|
+
print("HTTP Status Code: \(httpResponse.statusCode)")
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
task.resume()
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
//MARK: - OTP Verification Api
|
|
1625
|
+
func otpVerificationApi() {
|
|
1626
|
+
showLoadingIndicator()
|
|
1627
|
+
|
|
1628
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
1629
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.verifyOtp.path()
|
|
1630
|
+
|
|
1631
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1632
|
+
print("Invalid URL")
|
|
1633
|
+
hideLoadingIndicator()
|
|
1634
|
+
return
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
var request = URLRequest(url: serviceURL)
|
|
1638
|
+
request.httpMethod = "POST"
|
|
1639
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1640
|
+
|
|
1641
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1642
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1643
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1644
|
+
|
|
1645
|
+
let params: [String: Any] = [
|
|
1646
|
+
"card_search_value": txtFieldEmail.text ?? "",
|
|
1647
|
+
"card_search_key": "email",
|
|
1648
|
+
"otp": getCombinedOTP()
|
|
1649
|
+
]
|
|
1650
|
+
|
|
1651
|
+
do {
|
|
1652
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
1653
|
+
request.httpBody = jsonData
|
|
1654
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1655
|
+
print("JSON Payload: \(jsonString)")
|
|
1656
|
+
}
|
|
1657
|
+
} catch let error {
|
|
1658
|
+
print("Error creating JSON data: \(error)")
|
|
1659
|
+
hideLoadingIndicator()
|
|
1660
|
+
return
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
let session = URLSession.shared
|
|
1664
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
1665
|
+
|
|
1666
|
+
DispatchQueue.main.async {
|
|
1667
|
+
self.hideLoadingIndicator()
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
if let error = error {
|
|
1671
|
+
print("Error: \(error.localizedDescription)")
|
|
1672
|
+
return
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
1676
|
+
print("Invalid response")
|
|
1677
|
+
return
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
1681
|
+
if let data = serviceData {
|
|
1682
|
+
do {
|
|
1683
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
1684
|
+
|
|
1685
|
+
UserStoreSingleton.shared.isLoggedIn = true
|
|
1686
|
+
|
|
1687
|
+
print("Response Data: \(responseObject)")
|
|
1688
|
+
|
|
1689
|
+
UserStoreSingleton.shared.isLoggedIn = true
|
|
1690
|
+
|
|
1691
|
+
if let responseData = responseObject["data"] as? [String: Any],
|
|
1692
|
+
let data = responseData["data"] as? [String: Any],
|
|
1693
|
+
let customerId = data["customer_id"] as? String,
|
|
1694
|
+
let customerToken = data["customer_token"] as? String {
|
|
1695
|
+
|
|
1696
|
+
// Save customer ID and token
|
|
1697
|
+
UserStoreSingleton.shared.customerId = customerId
|
|
1698
|
+
UserStoreSingleton.shared.customerToken = customerToken
|
|
1699
|
+
|
|
1700
|
+
// Update UI-related or main thread operations
|
|
1701
|
+
DispatchQueue.main.async {
|
|
1702
|
+
UserStoreSingleton.shared.verificationEmail = self.txtFieldEmail.text
|
|
1703
|
+
|
|
1704
|
+
print("Customer ID successfully saved: \(UserStoreSingleton.shared.customerId ?? "None")")
|
|
1705
|
+
print("Customer Token successfully saved: \(UserStoreSingleton.shared.customerToken ?? "None")")
|
|
1706
|
+
print("Customer email successfully saved: \(UserStoreSingleton.shared.verificationEmail ?? "None")")
|
|
1707
|
+
|
|
1708
|
+
self.btnSettings.isHidden = false
|
|
1709
|
+
|
|
1710
|
+
// Check if customerId is nil or empty and update UI
|
|
1711
|
+
if self.selectedPaymentMethod == "Card" {
|
|
1712
|
+
if customerId.isEmpty {
|
|
1713
|
+
self.OTPView.isHidden = true
|
|
1714
|
+
self.viewCardFields.isHidden = false
|
|
1715
|
+
self.viewSingleSavedCard.isHidden = true
|
|
1716
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
1717
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
1718
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
1719
|
+
self.viewChangeCard.isHidden = true
|
|
1720
|
+
self.viewUpdateCard.isHidden = true
|
|
1721
|
+
self.viewAddNewCard.isHidden = true
|
|
1722
|
+
}
|
|
1723
|
+
else {
|
|
1724
|
+
self.getShowCardsApi()
|
|
1725
|
+
self.OTPView.isHidden = true
|
|
1726
|
+
self.viewCardFields.isHidden = true
|
|
1727
|
+
self.viewSingleSavedCard.isHidden = false
|
|
1728
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
1729
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
1730
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
1731
|
+
self.viewChangeCard.isHidden = true
|
|
1732
|
+
self.viewUpdateCard.isHidden = true
|
|
1733
|
+
self.viewAddNewCard.isHidden = true
|
|
1734
|
+
|
|
1735
|
+
self.viewTxtFieldCVVSingleCard.isHidden = true
|
|
1736
|
+
self.btnPayNowSingleCard.isHidden = true
|
|
1737
|
+
self.viewSingleSavedCardHeight.constant = 60
|
|
1738
|
+
self.btnNext.isHidden = true
|
|
1739
|
+
self.btnNextHeight.constant = 0
|
|
1740
|
+
self.btnNextTopCon.constant = 8
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
else if self.selectedPaymentMethod == "Bank" {
|
|
1744
|
+
self.getShowBankAccountsApi()
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
} else {
|
|
1749
|
+
print("Invalid JSON format")
|
|
1750
|
+
}
|
|
1751
|
+
} catch let jsonError {
|
|
1752
|
+
print("Error parsing JSON: \(jsonError)")
|
|
1753
|
+
}
|
|
1754
|
+
} else {
|
|
1755
|
+
print("No data received")
|
|
1756
|
+
}
|
|
1757
|
+
} else {
|
|
1758
|
+
print("HTTP Status Code: \(httpResponse.statusCode)")
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
task.resume()
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
//MARK: - GET Show Cards API
|
|
1765
|
+
func getShowCardsApi() {
|
|
1766
|
+
showLoadingIndicator()
|
|
1767
|
+
|
|
1768
|
+
// var components = URLComponents()
|
|
1769
|
+
// components.scheme = "https"
|
|
1770
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
1771
|
+
// components.path = "/api/v1/card"
|
|
1772
|
+
//
|
|
1773
|
+
// guard let serviceURL = components.url else {
|
|
1774
|
+
// print("Invalid URL")
|
|
1775
|
+
// hideLoadingIndicator()
|
|
1776
|
+
// return
|
|
1777
|
+
// }
|
|
1778
|
+
|
|
1779
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
1780
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.getCards.path()
|
|
1781
|
+
|
|
1782
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1783
|
+
print("Invalid URL")
|
|
1784
|
+
hideLoadingIndicator()
|
|
1785
|
+
return
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
var request = URLRequest(url: serviceURL)
|
|
1789
|
+
request.httpMethod = "GET"
|
|
1790
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1791
|
+
|
|
1792
|
+
let token = UserStoreSingleton.shared.customerToken
|
|
1793
|
+
print("Setting customerToken header: \(token ?? "None")")
|
|
1794
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Customer-Token")
|
|
1795
|
+
|
|
1796
|
+
let session = URLSession.shared
|
|
1797
|
+
let task = session.dataTask(with: request) { [weak self] (data, response, error) in
|
|
1798
|
+
guard let self = self else { return }
|
|
1799
|
+
|
|
1800
|
+
DispatchQueue.main.async {
|
|
1801
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
if let error = error {
|
|
1805
|
+
print("Error: \(error.localizedDescription)")
|
|
1806
|
+
return
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
guard let data = data else { return }
|
|
1810
|
+
|
|
1811
|
+
do {
|
|
1812
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
1813
|
+
let cards = jsonResponse["Cards"] as? [[String: Any]] {
|
|
1814
|
+
|
|
1815
|
+
// Map JSON response to CardModel array
|
|
1816
|
+
self.savedCards = cards.compactMap { cardDict in
|
|
1817
|
+
return CardModel(
|
|
1818
|
+
cardBrandName: cardDict["card_brand_name"] as? String ?? "",
|
|
1819
|
+
cardId: cardDict["card_id"] as? String ?? "",
|
|
1820
|
+
cardType: cardDict["card_type"] as? String ?? "",
|
|
1821
|
+
ccLast4: cardDict["cc_last_4"] as? String ?? "",
|
|
1822
|
+
ccValidThru: cardDict["cc_valid_thru"] as? String ?? "",
|
|
1823
|
+
customerId: cardDict["customer_id"] as? String ?? "",
|
|
1824
|
+
isDefault: (cardDict["is_default"] as? Int ?? 0) == 1
|
|
1825
|
+
)
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
DispatchQueue.main.async {
|
|
1829
|
+
if let firstCard = self.savedCards.first {
|
|
1830
|
+
self.lblCardNumberSigleSavedCard.text = "****\(firstCard.ccLast4)"
|
|
1831
|
+
self.lblExpireDateSingelSavedCard.text = "Expiry: \(firstCard.ccValidThru)"
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
self.tblViewSavedCardsList.reloadData()
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
} catch {
|
|
1838
|
+
print("Failed to parse response: \(error.localizedDescription)")
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
task.resume()
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// MARK: - Credit Card Charge Api If Billing info is nil and Without Login.
|
|
1845
|
+
func paymentIntentApi() {
|
|
1846
|
+
showLoadingIndicator()
|
|
1847
|
+
|
|
1848
|
+
// var components = URLComponents()
|
|
1849
|
+
// components.scheme = "https"
|
|
1850
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
1851
|
+
// components.path = "/api/v1/charges"
|
|
1852
|
+
//
|
|
1853
|
+
// guard let serviceURL = components.url else {
|
|
1854
|
+
// print("Invalid URL")
|
|
1855
|
+
// hideLoadingIndicator()
|
|
1856
|
+
// return
|
|
1857
|
+
// }
|
|
1858
|
+
|
|
1859
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
1860
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.creditCharges.path()
|
|
1861
|
+
|
|
1862
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1863
|
+
print("Invalid URL")
|
|
1864
|
+
hideLoadingIndicator()
|
|
1865
|
+
return
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
var request = URLRequest(url: serviceURL)
|
|
1869
|
+
request.httpMethod = "POST"
|
|
1870
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1871
|
+
|
|
1872
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1873
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1874
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1875
|
+
|
|
1876
|
+
let params: [String: Any] = [
|
|
1877
|
+
"name": cardNameTextField.text,
|
|
1878
|
+
"email": "test@gmail.com",
|
|
1879
|
+
"card_number": cardNumberTextField.text.replacingOccurrences(of: " ", with: ""),
|
|
1880
|
+
"cardholder_name": cardNameTextField.text,
|
|
1881
|
+
"exp_month": cardExpiryTextField.text.components(separatedBy: "/").first ?? "",
|
|
1882
|
+
"exp_year": cardExpiryTextField.text.components(separatedBy: "/").last ?? "",
|
|
1883
|
+
"cvc": cardCvvTextField.text,
|
|
1884
|
+
"description": "TestDescription",
|
|
1885
|
+
"currency": "usd",
|
|
1886
|
+
"payment_method": "card"
|
|
1887
|
+
]
|
|
1888
|
+
|
|
1889
|
+
do {
|
|
1890
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
1891
|
+
request.httpBody = jsonData
|
|
1892
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1893
|
+
print("JSON Payload: \(jsonString)")
|
|
1894
|
+
}
|
|
1895
|
+
} catch let error {
|
|
1896
|
+
print("Error creating JSON data: \(error)")
|
|
1897
|
+
hideLoadingIndicator()
|
|
1898
|
+
return
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
let session = URLSession.shared
|
|
1902
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
1903
|
+
|
|
1904
|
+
DispatchQueue.main.async {
|
|
1905
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
if let error = error {
|
|
1909
|
+
print("Error: \(error.localizedDescription)")
|
|
1910
|
+
return
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
1914
|
+
print("Invalid response")
|
|
1915
|
+
return
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
1919
|
+
if let data = serviceData {
|
|
1920
|
+
do {
|
|
1921
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
1922
|
+
print("Response Data: \(responseObject)")
|
|
1923
|
+
|
|
1924
|
+
// Check if status is 0 and handle the error
|
|
1925
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
1926
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
1927
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
1928
|
+
} else {
|
|
1929
|
+
DispatchQueue.main.async {
|
|
1930
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
1931
|
+
paymentDoneVC.chargeData = responseObject
|
|
1932
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1933
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
1934
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
} else {
|
|
1939
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
1940
|
+
}
|
|
1941
|
+
} catch let jsonError {
|
|
1942
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
1943
|
+
}
|
|
1944
|
+
} else {
|
|
1945
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
1946
|
+
}
|
|
1947
|
+
} else {
|
|
1948
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
task.resume()
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
// MARK: - Credit Card Charge Api from Saved cards If Billing info is nil and if Logged in.
|
|
1955
|
+
func paymentIntentFromShowSavedCardApi() {
|
|
1956
|
+
showLoadingIndicator()
|
|
1957
|
+
|
|
1958
|
+
// var components = URLComponents()
|
|
1959
|
+
// components.scheme = "https"
|
|
1960
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
1961
|
+
// components.path = "/api/v1/charges"
|
|
1962
|
+
//
|
|
1963
|
+
// guard let serviceURL = components.url else {
|
|
1964
|
+
// print("Invalid URL")
|
|
1965
|
+
// hideLoadingIndicator()
|
|
1966
|
+
// return
|
|
1967
|
+
// }
|
|
1968
|
+
|
|
1969
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
1970
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.creditCharges.path()
|
|
1971
|
+
|
|
1972
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1973
|
+
print("Invalid URL")
|
|
1974
|
+
hideLoadingIndicator()
|
|
1975
|
+
return
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
var request = URLRequest(url: serviceURL)
|
|
1979
|
+
request.httpMethod = "POST"
|
|
1980
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1981
|
+
|
|
1982
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1983
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1984
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1985
|
+
|
|
1986
|
+
// Prepare parameters for the API request
|
|
1987
|
+
let params: [String: Any] = [
|
|
1988
|
+
"name": UserStoreSingleton.shared.verificationEmail?.split(separator: "@").first ?? "",
|
|
1989
|
+
"email": UserStoreSingleton.shared.verificationEmail ?? "",
|
|
1990
|
+
"description": "TestDescription",
|
|
1991
|
+
"currency": "usd",
|
|
1992
|
+
"payment_method": "card",
|
|
1993
|
+
"save_card": 0,
|
|
1994
|
+
"customer": selectedCard?.customerId ?? "", // Use the selectedCard's customerId
|
|
1995
|
+
"card_id": selectedCard?.cardId ?? "", // Use the selectedCard's cardId
|
|
1996
|
+
"cvc": txtFieldCVVSingleSavedCard.text ?? "",
|
|
1997
|
+
"customer_id": selectedCard?.customerId ?? ""
|
|
1998
|
+
]
|
|
1999
|
+
|
|
2000
|
+
print(params)
|
|
2001
|
+
|
|
2002
|
+
do {
|
|
2003
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2004
|
+
request.httpBody = jsonData
|
|
2005
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2006
|
+
print("JSON Payload: \(jsonString)")
|
|
2007
|
+
}
|
|
2008
|
+
} catch let error {
|
|
2009
|
+
print("Error creating JSON data: \(error)")
|
|
2010
|
+
hideLoadingIndicator()
|
|
2011
|
+
return
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
let session = URLSession.shared
|
|
2015
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2016
|
+
|
|
2017
|
+
DispatchQueue.main.async {
|
|
2018
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
if let error = error {
|
|
2022
|
+
print("Error: \(error.localizedDescription)")
|
|
2023
|
+
return
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2027
|
+
print("Invalid response")
|
|
2028
|
+
return
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2032
|
+
if let data = serviceData {
|
|
2033
|
+
do {
|
|
2034
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2035
|
+
print("Response Data: \(responseObject)")
|
|
2036
|
+
|
|
2037
|
+
// Check if status is 0 and handle the error
|
|
2038
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
2039
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
2040
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
2041
|
+
} else {
|
|
2042
|
+
DispatchQueue.main.async {
|
|
2043
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
2044
|
+
paymentDoneVC.chargeData = responseObject
|
|
2045
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
2046
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
2047
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
} else {
|
|
2052
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2053
|
+
}
|
|
2054
|
+
} catch let jsonError {
|
|
2055
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2056
|
+
}
|
|
2057
|
+
} else {
|
|
2058
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2059
|
+
}
|
|
2060
|
+
} else {
|
|
2061
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
task.resume()
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
//MARK: - Credit Card Charge Api from Add new cards If Billing info is nil and Logged in.
|
|
2068
|
+
func paymentIntentFromAddNewCardApi(customerId: String?) {
|
|
2069
|
+
showLoadingIndicator()
|
|
2070
|
+
|
|
2071
|
+
// var components = URLComponents()
|
|
2072
|
+
// components.scheme = "https"
|
|
2073
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2074
|
+
// components.path = "/api/v1/charges"
|
|
2075
|
+
//
|
|
2076
|
+
// guard let serviceURL = components.url else {
|
|
2077
|
+
// print("Invalid URL")
|
|
2078
|
+
// hideLoadingIndicator()
|
|
2079
|
+
// return
|
|
2080
|
+
// }
|
|
2081
|
+
|
|
2082
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2083
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.creditCharges.path()
|
|
2084
|
+
|
|
2085
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2086
|
+
print("Invalid URL")
|
|
2087
|
+
hideLoadingIndicator()
|
|
2088
|
+
return
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
var request = URLRequest(url: serviceURL)
|
|
2092
|
+
request.httpMethod = "POST"
|
|
2093
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2094
|
+
|
|
2095
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
2096
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
2097
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
2098
|
+
|
|
2099
|
+
// Get the text fields from the selected cell and trim whitespace
|
|
2100
|
+
let nameText = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2101
|
+
let cvvText = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2102
|
+
let cardNumberText = (txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "").replacingOccurrences(of: " ", with: "")
|
|
2103
|
+
let expiryText = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2104
|
+
|
|
2105
|
+
|
|
2106
|
+
// Check if any field is empty
|
|
2107
|
+
if cardNumberText.isEmpty || expiryText.isEmpty || cvvText.isEmpty || nameText.isEmpty {
|
|
2108
|
+
let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
|
|
2109
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2110
|
+
self.present(alert, animated: true, completion: nil)
|
|
2111
|
+
return
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
// Validate expiry date format
|
|
2115
|
+
let expiryDateFormat = "MM/yyyy"
|
|
2116
|
+
let dateFormatter = DateFormatter()
|
|
2117
|
+
dateFormatter.dateFormat = expiryDateFormat
|
|
2118
|
+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
2119
|
+
|
|
2120
|
+
// Split the expiry date and validate its format
|
|
2121
|
+
let exp = expiryText.split(separator: "/")
|
|
2122
|
+
if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
|
|
2123
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
2124
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2125
|
+
self.present(alert, animated: true, completion: nil)
|
|
2126
|
+
return
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
// Check if the expiry date is valid
|
|
2130
|
+
if let expiryDateObj = dateFormatter.date(from: expiryText) {
|
|
2131
|
+
// Check if the expiry date is in the past
|
|
2132
|
+
let currentDate = Date()
|
|
2133
|
+
let calendar = Calendar.current
|
|
2134
|
+
let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
|
|
2135
|
+
if expiryDateObj < currentMonthYear! {
|
|
2136
|
+
let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
|
|
2137
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2138
|
+
self.present(alert, animated: true, completion: nil)
|
|
2139
|
+
return
|
|
2140
|
+
}
|
|
2141
|
+
} else {
|
|
2142
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
2143
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2144
|
+
self.present(alert, animated: true, completion: nil)
|
|
2145
|
+
return
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
|
|
2149
|
+
let emailPrefix = UserStoreSingleton.shared.verificationEmail?.components(separatedBy: "@").first ?? ""
|
|
2150
|
+
|
|
2151
|
+
var params: [String: Any] = [
|
|
2152
|
+
"name": nameText,
|
|
2153
|
+
"card_number": cardNumberText,
|
|
2154
|
+
"cardholder_name": nameText,
|
|
2155
|
+
"exp_month": expiryText.components(separatedBy: "/").first ?? "",
|
|
2156
|
+
"exp_year": expiryText.components(separatedBy: "/").last ?? "",
|
|
2157
|
+
"cvc": cvvText,
|
|
2158
|
+
"description": "TestDescription",
|
|
2159
|
+
"currency": "usd",
|
|
2160
|
+
"payment_method": "card",
|
|
2161
|
+
"save_card": isSavedNewCardForFuture ? 1 : 0,
|
|
2162
|
+
"email" : UserStoreSingleton.shared.verificationEmail ?? ""
|
|
2163
|
+
]
|
|
2164
|
+
|
|
2165
|
+
// Add is_default parameter if save_card is 1
|
|
2166
|
+
if isSavedNewCardForFuture {
|
|
2167
|
+
params["is_default"] = "1"
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
if let customerId = customerId {
|
|
2171
|
+
params["customer"] = customerId
|
|
2172
|
+
params["customer_id"] = customerId
|
|
2173
|
+
} else {
|
|
2174
|
+
params["username"] = emailPrefix
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
print(params)
|
|
2178
|
+
|
|
2179
|
+
do {
|
|
2180
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2181
|
+
request.httpBody = jsonData
|
|
2182
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2183
|
+
print("JSON Payload: \(jsonString)")
|
|
2184
|
+
}
|
|
2185
|
+
} catch let error {
|
|
2186
|
+
print("Error creating JSON data: \(error)")
|
|
2187
|
+
hideLoadingIndicator()
|
|
2188
|
+
return
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
let session = URLSession.shared
|
|
2192
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2193
|
+
|
|
2194
|
+
DispatchQueue.main.async {
|
|
2195
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
if let error = error {
|
|
2199
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
2200
|
+
return
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2204
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
2205
|
+
return
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2209
|
+
if let data = serviceData {
|
|
2210
|
+
do {
|
|
2211
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2212
|
+
print("Response Data: \(responseObject)")
|
|
2213
|
+
|
|
2214
|
+
// Check if status is 0 and handle the error
|
|
2215
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
2216
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
2217
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
2218
|
+
} else {
|
|
2219
|
+
DispatchQueue.main.async {
|
|
2220
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
2221
|
+
paymentDoneVC.chargeData = responseObject
|
|
2222
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
2223
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
2224
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
} else {
|
|
2229
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2230
|
+
}
|
|
2231
|
+
} catch let jsonError {
|
|
2232
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2233
|
+
}
|
|
2234
|
+
} else {
|
|
2235
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2236
|
+
}
|
|
2237
|
+
} else {
|
|
2238
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
task.resume()
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
//MARK: - Update Cards Api.
|
|
2245
|
+
func updateCardApi(cardID: String) {
|
|
2246
|
+
showLoadingIndicator()
|
|
2247
|
+
|
|
2248
|
+
// var components = URLComponents()
|
|
2249
|
+
// components.scheme = "https"
|
|
2250
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2251
|
+
// components.path = "/api/v1/card/\(cardID)" // Append the card_id to the path
|
|
2252
|
+
//
|
|
2253
|
+
// guard let serviceURL = components.url else {
|
|
2254
|
+
// print("Invalid URL")
|
|
2255
|
+
// hideLoadingIndicator()
|
|
2256
|
+
// return
|
|
2257
|
+
// }
|
|
2258
|
+
|
|
2259
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2260
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.getCards.path()+"/\(cardID)"
|
|
2261
|
+
|
|
2262
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2263
|
+
print("Invalid URL")
|
|
2264
|
+
hideLoadingIndicator()
|
|
2265
|
+
return
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
var request = URLRequest(url: serviceURL)
|
|
2269
|
+
request.httpMethod = "PUT"
|
|
2270
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2271
|
+
|
|
2272
|
+
let token = UserStoreSingleton.shared.customerToken
|
|
2273
|
+
print("Setting customerToken header: \(token ?? "None")")
|
|
2274
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Customer-Token")
|
|
2275
|
+
|
|
2276
|
+
// Get the text fields from the selected cell and trim whitespace
|
|
2277
|
+
let nameText = txtFieldNameOnCardUpdateCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2278
|
+
let cvvText = txtFieldCVVUpdateCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2279
|
+
let expiryText = txtFieldExpireDateUpdateCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2280
|
+
|
|
2281
|
+
// Check if any field is empty
|
|
2282
|
+
if expiryText.isEmpty || cvvText.isEmpty || nameText.isEmpty {
|
|
2283
|
+
let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
|
|
2284
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2285
|
+
self.present(alert, animated: true, completion: nil)
|
|
2286
|
+
return
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
// Validate expiry date format
|
|
2290
|
+
let expiryDateFormat = "MM/yyyy"
|
|
2291
|
+
let dateFormatter = DateFormatter()
|
|
2292
|
+
dateFormatter.dateFormat = expiryDateFormat
|
|
2293
|
+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
2294
|
+
|
|
2295
|
+
// Split the expiry date and validate its format
|
|
2296
|
+
let exp = expiryText.split(separator: "/")
|
|
2297
|
+
if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
|
|
2298
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
2299
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2300
|
+
self.present(alert, animated: true, completion: nil)
|
|
2301
|
+
return
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
// Check if the expiry date is valid
|
|
2305
|
+
if let expiryDateObj = dateFormatter.date(from: expiryText) {
|
|
2306
|
+
// Check if the expiry date is in the past
|
|
2307
|
+
let currentDate = Date()
|
|
2308
|
+
let calendar = Calendar.current
|
|
2309
|
+
let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
|
|
2310
|
+
if expiryDateObj < currentMonthYear! {
|
|
2311
|
+
let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
|
|
2312
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2313
|
+
self.present(alert, animated: true, completion: nil)
|
|
2314
|
+
return
|
|
2315
|
+
}
|
|
2316
|
+
} else {
|
|
2317
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
2318
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
2319
|
+
self.present(alert, animated: true, completion: nil)
|
|
2320
|
+
return
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
// Set up parameters with selected card details
|
|
2324
|
+
let params: [String: Any] = [
|
|
2325
|
+
"card_id": cardID,
|
|
2326
|
+
"cardholder_name": nameText,
|
|
2327
|
+
"cvc": cvvText,
|
|
2328
|
+
"exp_month": expiryText.components(separatedBy: "/").first ?? "",
|
|
2329
|
+
"exp_year": expiryText.components(separatedBy: "/").last ?? "",
|
|
2330
|
+
]
|
|
2331
|
+
|
|
2332
|
+
print(params)
|
|
2333
|
+
|
|
2334
|
+
do {
|
|
2335
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2336
|
+
request.httpBody = jsonData
|
|
2337
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2338
|
+
print("JSON Payload: \(jsonString)")
|
|
2339
|
+
}
|
|
2340
|
+
} catch let error {
|
|
2341
|
+
print("Error creating JSON data: \(error)")
|
|
2342
|
+
hideLoadingIndicator()
|
|
2343
|
+
return
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
let session = URLSession.shared
|
|
2347
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2348
|
+
|
|
2349
|
+
DispatchQueue.main.async {
|
|
2350
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
if let error = error {
|
|
2354
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
2355
|
+
return
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2359
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
2360
|
+
return
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2364
|
+
if let data = serviceData {
|
|
2365
|
+
do {
|
|
2366
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2367
|
+
print("Response Data: \(responseObject)")
|
|
2368
|
+
DispatchQueue.main.async {
|
|
2369
|
+
|
|
2370
|
+
self.viewUpdateCard.isHidden = true
|
|
2371
|
+
self.viewChangeCard.isHidden = false
|
|
2372
|
+
self.OTPView.isHidden = true
|
|
2373
|
+
self.viewCardFields.isHidden = true
|
|
2374
|
+
self.viewSingleSavedCard.isHidden = true
|
|
2375
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
2376
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
2377
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
2378
|
+
self.viewUpdateCard.isHidden = true
|
|
2379
|
+
self.viewAddNewCard.isHidden = true
|
|
2380
|
+
self.btnNext.isHidden = true
|
|
2381
|
+
self.btnNextHeight.constant = 0
|
|
2382
|
+
self.btnNextTopCon.constant = 8
|
|
2383
|
+
|
|
2384
|
+
self.getShowCardsApi()
|
|
2385
|
+
|
|
2386
|
+
self.txtFieldNameOnCardUpdateCardView.text = ""
|
|
2387
|
+
self.txtFieldExpireDateUpdateCardView.text = ""
|
|
2388
|
+
self.txtFieldCVVUpdateCardView.text = ""
|
|
2389
|
+
}
|
|
2390
|
+
} else {
|
|
2391
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2392
|
+
}
|
|
2393
|
+
} catch let jsonError {
|
|
2394
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2395
|
+
}
|
|
2396
|
+
} else {
|
|
2397
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2398
|
+
}
|
|
2399
|
+
} else {
|
|
2400
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
task.resume()
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
//MARK: - Delete Cards Api.
|
|
2407
|
+
func deleteCardApi(cardID: String, at index: Int) {
|
|
2408
|
+
showLoadingIndicator()
|
|
2409
|
+
|
|
2410
|
+
// var components = URLComponents()
|
|
2411
|
+
// components.scheme = "https"
|
|
2412
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2413
|
+
// components.path = "/api/v1/card/\(cardID)" // Append the card_id to the path
|
|
2414
|
+
//
|
|
2415
|
+
// guard let serviceURL = components.url else {
|
|
2416
|
+
// print("Invalid URL")
|
|
2417
|
+
// hideLoadingIndicator()
|
|
2418
|
+
// return
|
|
2419
|
+
// }
|
|
2420
|
+
|
|
2421
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2422
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.getCards.path()+"/\(cardID)"
|
|
2423
|
+
|
|
2424
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2425
|
+
print("Invalid URL")
|
|
2426
|
+
hideLoadingIndicator()
|
|
2427
|
+
return
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
var request = URLRequest(url: serviceURL)
|
|
2431
|
+
request.httpMethod = "DELETE"
|
|
2432
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2433
|
+
|
|
2434
|
+
let token = UserStoreSingleton.shared.customerToken
|
|
2435
|
+
print("Setting customerToken header: \(token ?? "None")")
|
|
2436
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Customer-Token")
|
|
2437
|
+
|
|
2438
|
+
let session = URLSession.shared
|
|
2439
|
+
let task = session.dataTask(with: request) { [weak self] (serviceData, serviceResponse, error) in
|
|
2440
|
+
guard let self = self else { return }
|
|
2441
|
+
|
|
2442
|
+
DispatchQueue.main.async {
|
|
2443
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
if let error = error {
|
|
2447
|
+
DispatchQueue.main.async {
|
|
2448
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
2449
|
+
}
|
|
2450
|
+
return
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2454
|
+
DispatchQueue.main.async {
|
|
2455
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
2456
|
+
}
|
|
2457
|
+
return
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2461
|
+
|
|
2462
|
+
if let data = serviceData {
|
|
2463
|
+
do {
|
|
2464
|
+
// Try to parse the data as JSON
|
|
2465
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
2466
|
+
let message = jsonResponse["message"] as? String {
|
|
2467
|
+
DispatchQueue.main.async {
|
|
2468
|
+
self.showToast(message: message)
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
} catch let jsonError {
|
|
2472
|
+
print("Error parsing JSON response: \(jsonError.localizedDescription)")
|
|
2473
|
+
}
|
|
2474
|
+
} else {
|
|
2475
|
+
print("No data received.")
|
|
2476
|
+
}
|
|
2477
|
+
} else {
|
|
2478
|
+
DispatchQueue.main.async {
|
|
2479
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
task.resume()
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
func presentPaymentErrorVC(errorMessage: String) {
|
|
2487
|
+
DispatchQueue.main.async {
|
|
2488
|
+
if let paymentErrorVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentErrorVC") as? PaymentErrorVC {
|
|
2489
|
+
paymentErrorVC.errorMessage = errorMessage
|
|
2490
|
+
paymentErrorVC.easyPayDelegate = self.easyPayDelegate // Pass the reference here
|
|
2491
|
+
self.navigationController?.pushViewController(paymentErrorVC, animated: true)
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
//MARK: - Bank Api's
|
|
2497
|
+
|
|
2498
|
+
//MARK: - GET Show Bank Accounts API
|
|
2499
|
+
func getShowBankAccountsApi() {
|
|
2500
|
+
showLoadingIndicator()
|
|
2501
|
+
|
|
2502
|
+
// var components = URLComponents()
|
|
2503
|
+
// components.scheme = "https"
|
|
2504
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2505
|
+
// components.path = "/api/v1/ach/account"
|
|
2506
|
+
//
|
|
2507
|
+
// guard let serviceURL = components.url else {
|
|
2508
|
+
// print("Invalid URL")
|
|
2509
|
+
// hideLoadingIndicator()
|
|
2510
|
+
// return
|
|
2511
|
+
// }
|
|
2512
|
+
|
|
2513
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2514
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.account.path()
|
|
2515
|
+
|
|
2516
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2517
|
+
print("Invalid URL")
|
|
2518
|
+
hideLoadingIndicator()
|
|
2519
|
+
return
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
var request = URLRequest(url: serviceURL)
|
|
2523
|
+
request.httpMethod = "GET"
|
|
2524
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2525
|
+
|
|
2526
|
+
let token = UserStoreSingleton.shared.customerToken
|
|
2527
|
+
print("Setting customerToken header: \(token ?? "None")")
|
|
2528
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Customer-Token")
|
|
2529
|
+
|
|
2530
|
+
let session = URLSession.shared
|
|
2531
|
+
let task = session.dataTask(with: request) { [weak self] (data, response, error) in
|
|
2532
|
+
guard let self = self else { return }
|
|
2533
|
+
|
|
2534
|
+
DispatchQueue.main.async {
|
|
2535
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
if let error = error {
|
|
2539
|
+
print("Error: \(error.localizedDescription)")
|
|
2540
|
+
return
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
guard let data = data else { return }
|
|
2544
|
+
|
|
2545
|
+
do {
|
|
2546
|
+
let decoder = JSONDecoder()
|
|
2547
|
+
let bankAccountModel = try decoder.decode(BankAccountModel.self, from: data)
|
|
2548
|
+
|
|
2549
|
+
if bankAccountModel.status == true {
|
|
2550
|
+
// Update bankAccounts array on the main thread
|
|
2551
|
+
DispatchQueue.main.async {
|
|
2552
|
+
self.bankAccounts = bankAccountModel.accounts ?? []
|
|
2553
|
+
|
|
2554
|
+
if let firstAccount = self.bankAccounts.first {
|
|
2555
|
+
// Set the account number and account type in the labels
|
|
2556
|
+
self.selectedbankAccounts = firstAccount
|
|
2557
|
+
|
|
2558
|
+
self.lblAccountNumberSingleAccountView.text = "****\(firstAccount.account_number_last_4 ?? "")"
|
|
2559
|
+
self.lblAccountTypeSingleAccountView.text = "Type: \(firstAccount.account_type ?? "")"
|
|
2560
|
+
}
|
|
2561
|
+
|
|
2562
|
+
self.tblViewSavedBankAccounts.reloadData()
|
|
2563
|
+
|
|
2564
|
+
self.viewSingleSavedAccount.isHidden = false
|
|
2565
|
+
self.viewBankFields.isHidden = true
|
|
2566
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
2567
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
2568
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
2569
|
+
self.OTPView.isHidden = true
|
|
2570
|
+
self.emailView.isHidden = true
|
|
2571
|
+
self.viewCardFields.isHidden = true
|
|
2572
|
+
self.viewSingleSavedCard.isHidden = true
|
|
2573
|
+
self.viewChangeCard.isHidden = true
|
|
2574
|
+
self.viewUpdateCard.isHidden = true
|
|
2575
|
+
self.viewAddNewCard.isHidden = true
|
|
2576
|
+
self.btnNext.isHidden = true
|
|
2577
|
+
self.btnNextHeight.constant = 0
|
|
2578
|
+
self.btnNextTopCon.constant = 8
|
|
2579
|
+
|
|
2580
|
+
self.viewNewBankAccount.isHidden = true
|
|
2581
|
+
self.viewCrypto.isHidden = true
|
|
2582
|
+
|
|
2583
|
+
self.viewTermsAndConditions.isHidden = true
|
|
2584
|
+
|
|
2585
|
+
self.viewChangedAccount.isHidden = true
|
|
2586
|
+
|
|
2587
|
+
if self.isSelectForPayBank {
|
|
2588
|
+
self.viewTermAndConditionsSingleAccountView.isHidden = false
|
|
2589
|
+
self.btnPayNowSingleAccountView.isHidden = false
|
|
2590
|
+
self.viewSingleAccountViewHeight.constant = 170
|
|
2591
|
+
} else {
|
|
2592
|
+
self.viewTermAndConditionsSingleAccountView.isHidden = true
|
|
2593
|
+
self.btnPayNowSingleAccountView.isHidden = true
|
|
2594
|
+
self.viewSingleAccountViewHeight.constant = 68
|
|
2595
|
+
self.btnNext.isHidden = true
|
|
2596
|
+
self.btnNextHeight.constant = 0
|
|
2597
|
+
self.btnNextTopCon.constant = 0
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
} else {
|
|
2601
|
+
// Handle the error or show a message
|
|
2602
|
+
print("Error: \(bankAccountModel.message ?? "Unknown error")")
|
|
2603
|
+
}
|
|
2604
|
+
} catch {
|
|
2605
|
+
print("Failed to parse response: \(error.localizedDescription)")
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
task.resume()
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
//MARK: - Banking Account Charge Api If Billing info is nil and without Login
|
|
2613
|
+
func accountChargeApi() {
|
|
2614
|
+
showLoadingIndicator()
|
|
2615
|
+
|
|
2616
|
+
// var components = URLComponents()
|
|
2617
|
+
// components.scheme = "https"
|
|
2618
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2619
|
+
// components.path = "/api/v1/ach/charge"
|
|
2620
|
+
//
|
|
2621
|
+
// guard let serviceURL = components.url else {
|
|
2622
|
+
// print("Invalid URL")
|
|
2623
|
+
// hideLoadingIndicator()
|
|
2624
|
+
// return
|
|
2625
|
+
// }
|
|
2626
|
+
|
|
2627
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2628
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
2629
|
+
|
|
2630
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2631
|
+
print("Invalid URL")
|
|
2632
|
+
hideLoadingIndicator()
|
|
2633
|
+
return
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
var request = URLRequest(url: serviceURL)
|
|
2637
|
+
request.httpMethod = "POST"
|
|
2638
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2639
|
+
|
|
2640
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
2641
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
2642
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
2643
|
+
|
|
2644
|
+
let params: [String: Any] = [
|
|
2645
|
+
"name": txtFieldAccountName.text ?? "",
|
|
2646
|
+
"email": "test@gmail.com",
|
|
2647
|
+
"description": "TestDescription",
|
|
2648
|
+
"currency": "usd",
|
|
2649
|
+
"account_type": txtFieldAccountType.text?.lowercased() ?? "",
|
|
2650
|
+
"routing_number": txtFieldRoutingNumber.text?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
2651
|
+
"account_number": txtFieldAccountNumber.text?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
2652
|
+
"payment_mode": "auth_and_capture",
|
|
2653
|
+
"payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
|
|
2654
|
+
"levelIndicator": 1,
|
|
2655
|
+
]
|
|
2656
|
+
|
|
2657
|
+
do {
|
|
2658
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2659
|
+
request.httpBody = jsonData
|
|
2660
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2661
|
+
print("JSON Payload: \(jsonString)")
|
|
2662
|
+
}
|
|
2663
|
+
} catch let error {
|
|
2664
|
+
print("Error creating JSON data: \(error)")
|
|
2665
|
+
hideLoadingIndicator()
|
|
2666
|
+
return
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
let session = URLSession.shared
|
|
2670
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2671
|
+
|
|
2672
|
+
DispatchQueue.main.async {
|
|
2673
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
if let error = error {
|
|
2677
|
+
print("Error: \(error.localizedDescription)")
|
|
2678
|
+
return
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2682
|
+
print("Invalid response")
|
|
2683
|
+
return
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2687
|
+
if let data = serviceData {
|
|
2688
|
+
do {
|
|
2689
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2690
|
+
print("Response Data: \(responseObject)")
|
|
2691
|
+
|
|
2692
|
+
// Check if status is 0 and handle the error
|
|
2693
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
2694
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
2695
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
2696
|
+
} else {
|
|
2697
|
+
DispatchQueue.main.async {
|
|
2698
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
2699
|
+
paymentDoneVC.chargeData = responseObject
|
|
2700
|
+
// Pass the selected payment method
|
|
2701
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
2702
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
|
|
2703
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
} else {
|
|
2708
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2709
|
+
}
|
|
2710
|
+
} catch let jsonError {
|
|
2711
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2712
|
+
}
|
|
2713
|
+
} else {
|
|
2714
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2715
|
+
}
|
|
2716
|
+
} else {
|
|
2717
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
task.resume()
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
//MARK: - Banking Account Charge Api from Regular saved bank account if Billing info is nil
|
|
2724
|
+
func accountChargeSavedBankAccountApi() {
|
|
2725
|
+
showLoadingIndicator()
|
|
2726
|
+
|
|
2727
|
+
// var components = URLComponents()
|
|
2728
|
+
// components.scheme = "https"
|
|
2729
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2730
|
+
// components.path = "/api/v1/ach/charge"
|
|
2731
|
+
//
|
|
2732
|
+
// guard let serviceURL = components.url else {
|
|
2733
|
+
// print("Invalid URL")
|
|
2734
|
+
// hideLoadingIndicator()
|
|
2735
|
+
// return
|
|
2736
|
+
// }
|
|
2737
|
+
|
|
2738
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2739
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
2740
|
+
|
|
2741
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2742
|
+
print("Invalid URL")
|
|
2743
|
+
hideLoadingIndicator()
|
|
2744
|
+
return
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
var request = URLRequest(url: serviceURL)
|
|
2748
|
+
request.httpMethod = "POST"
|
|
2749
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2750
|
+
|
|
2751
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
2752
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
2753
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
2754
|
+
|
|
2755
|
+
let params: [String: Any] = [
|
|
2756
|
+
"account_id": selectedbankAccounts?.account_id ?? "",
|
|
2757
|
+
"customer": selectedbankAccounts?.customer_id ?? "",
|
|
2758
|
+
"payment_method": "ach",
|
|
2759
|
+
"description": "Test Description",
|
|
2760
|
+
"currency": "usd",
|
|
2761
|
+
]
|
|
2762
|
+
|
|
2763
|
+
print(params)
|
|
2764
|
+
|
|
2765
|
+
do {
|
|
2766
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2767
|
+
request.httpBody = jsonData
|
|
2768
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2769
|
+
print("JSON Payload: \(jsonString)")
|
|
2770
|
+
}
|
|
2771
|
+
} catch let error {
|
|
2772
|
+
print("Error creating JSON data: \(error)")
|
|
2773
|
+
hideLoadingIndicator()
|
|
2774
|
+
return
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
let session = URLSession.shared
|
|
2778
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2779
|
+
|
|
2780
|
+
DispatchQueue.main.async {
|
|
2781
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
if let error = error {
|
|
2785
|
+
print("Error: \(error.localizedDescription)")
|
|
2786
|
+
return
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2790
|
+
print("Invalid response")
|
|
2791
|
+
return
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2795
|
+
if let data = serviceData {
|
|
2796
|
+
do {
|
|
2797
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2798
|
+
print("Response Data: \(responseObject)")
|
|
2799
|
+
|
|
2800
|
+
// Check if status is 0 and handle the error
|
|
2801
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
2802
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
2803
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
2804
|
+
} else {
|
|
2805
|
+
DispatchQueue.main.async {
|
|
2806
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
2807
|
+
paymentDoneVC.chargeData = responseObject
|
|
2808
|
+
// Pass the selected payment method
|
|
2809
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
2810
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
|
|
2811
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
} else {
|
|
2816
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2817
|
+
}
|
|
2818
|
+
} catch let jsonError {
|
|
2819
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2820
|
+
}
|
|
2821
|
+
} else {
|
|
2822
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2823
|
+
}
|
|
2824
|
+
} else {
|
|
2825
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
task.resume()
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
//MARK: - Banking Account Charge Api from add new account if billing info is nil and user not saved the account
|
|
2832
|
+
func accountChargeAddNewAccountApi() {
|
|
2833
|
+
showLoadingIndicator()
|
|
2834
|
+
|
|
2835
|
+
// var components = URLComponents()
|
|
2836
|
+
// components.scheme = "https"
|
|
2837
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2838
|
+
// components.path = "/api/v1/ach/charge"
|
|
2839
|
+
//
|
|
2840
|
+
// guard let serviceURL = components.url else {
|
|
2841
|
+
// print("Invalid URL")
|
|
2842
|
+
// hideLoadingIndicator()
|
|
2843
|
+
// return
|
|
2844
|
+
// }
|
|
2845
|
+
|
|
2846
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2847
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
2848
|
+
|
|
2849
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2850
|
+
print("Invalid URL")
|
|
2851
|
+
hideLoadingIndicator()
|
|
2852
|
+
return
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
var request = URLRequest(url: serviceURL)
|
|
2856
|
+
request.httpMethod = "POST"
|
|
2857
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2858
|
+
|
|
2859
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
2860
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
2861
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
2862
|
+
|
|
2863
|
+
let accountName = txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2864
|
+
let routingNumber = txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2865
|
+
let accountType = txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2866
|
+
let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2867
|
+
|
|
2868
|
+
let params: [String: Any] = [
|
|
2869
|
+
"name": accountName,
|
|
2870
|
+
"email": UserStoreSingleton.shared.verificationEmail ?? "",
|
|
2871
|
+
"description": "Test Description",
|
|
2872
|
+
"currency": "usd",
|
|
2873
|
+
"account_type": accountType.lowercased(),
|
|
2874
|
+
"routing_number": routingNumber,
|
|
2875
|
+
"account_number": accountNumber,
|
|
2876
|
+
"payment_mode": "auth_and_capture",
|
|
2877
|
+
"payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
|
|
2878
|
+
"levelIndicator": 1,
|
|
2879
|
+
]
|
|
2880
|
+
|
|
2881
|
+
print(params)
|
|
2882
|
+
|
|
2883
|
+
do {
|
|
2884
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
2885
|
+
request.httpBody = jsonData
|
|
2886
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
2887
|
+
print("JSON Payload: \(jsonString)")
|
|
2888
|
+
}
|
|
2889
|
+
} catch let error {
|
|
2890
|
+
print("Error creating JSON data: \(error)")
|
|
2891
|
+
hideLoadingIndicator()
|
|
2892
|
+
return
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
let session = URLSession.shared
|
|
2896
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
2897
|
+
|
|
2898
|
+
DispatchQueue.main.async {
|
|
2899
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
if let error = error {
|
|
2903
|
+
print("Error: \(error.localizedDescription)")
|
|
2904
|
+
return
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
2908
|
+
print("Invalid response")
|
|
2909
|
+
return
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
2913
|
+
if let data = serviceData {
|
|
2914
|
+
do {
|
|
2915
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
2916
|
+
print("Response Data: \(responseObject)")
|
|
2917
|
+
|
|
2918
|
+
// Check if status is 0 and handle the error
|
|
2919
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
2920
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
2921
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
2922
|
+
} else {
|
|
2923
|
+
DispatchQueue.main.async {
|
|
2924
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
2925
|
+
paymentDoneVC.chargeData = responseObject
|
|
2926
|
+
// Pass the selected payment method
|
|
2927
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
2928
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
|
|
2929
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
} else {
|
|
2934
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
2935
|
+
}
|
|
2936
|
+
} catch let jsonError {
|
|
2937
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
2938
|
+
}
|
|
2939
|
+
} else {
|
|
2940
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
2941
|
+
}
|
|
2942
|
+
} else {
|
|
2943
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
task.resume()
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
//MARK: - Account Charge Api if user saved the account.
|
|
2950
|
+
func accountChargeApi(customerId: String?) {
|
|
2951
|
+
showLoadingIndicator()
|
|
2952
|
+
|
|
2953
|
+
// var components = URLComponents()
|
|
2954
|
+
// components.scheme = "https"
|
|
2955
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
2956
|
+
// components.path = "/api/v1/ach/charge"
|
|
2957
|
+
//
|
|
2958
|
+
// guard let serviceURL = components.url else {
|
|
2959
|
+
// print("Invalid URL")
|
|
2960
|
+
// hideLoadingIndicator()
|
|
2961
|
+
// return
|
|
2962
|
+
// }
|
|
2963
|
+
|
|
2964
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
2965
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
|
|
2966
|
+
|
|
2967
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
2968
|
+
print("Invalid URL")
|
|
2969
|
+
hideLoadingIndicator()
|
|
2970
|
+
return
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
var request = URLRequest(url: serviceURL)
|
|
2974
|
+
request.httpMethod = "POST"
|
|
2975
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
2976
|
+
|
|
2977
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
2978
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
2979
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
2980
|
+
|
|
2981
|
+
// Retrieve and trim text field values (removing leading and trailing whitespace)
|
|
2982
|
+
let accountName = txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2983
|
+
let routingNumber = txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2984
|
+
let accountType = txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2985
|
+
let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
2986
|
+
|
|
2987
|
+
let emailPrefix = UserStoreSingleton.shared.verificationEmail?.components(separatedBy: "@").first ?? ""
|
|
2988
|
+
|
|
2989
|
+
var params: [String: Any] = [
|
|
2990
|
+
"name": accountName,
|
|
2991
|
+
"email": UserStoreSingleton.shared.verificationEmail ?? "",
|
|
2992
|
+
"description": "Test Description",
|
|
2993
|
+
"currency": "usd",
|
|
2994
|
+
"account_type": accountType.lowercased(),
|
|
2995
|
+
"routing_number": routingNumber,
|
|
2996
|
+
"account_number": accountNumber,
|
|
2997
|
+
"payment_mode": "auth_and_capture",
|
|
2998
|
+
"payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
|
|
2999
|
+
"levelIndicator": 1,
|
|
3000
|
+
"save_account": 1,
|
|
3001
|
+
"payment_method": "ach"
|
|
3002
|
+
]
|
|
3003
|
+
|
|
3004
|
+
if let customerId = customerId {
|
|
3005
|
+
params["customer"] = customerId
|
|
3006
|
+
} else {
|
|
3007
|
+
params["username"] = emailPrefix
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
print(params)
|
|
3011
|
+
|
|
3012
|
+
do {
|
|
3013
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
3014
|
+
request.httpBody = jsonData
|
|
3015
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
3016
|
+
print("JSON Payload: \(jsonString)")
|
|
3017
|
+
}
|
|
3018
|
+
} catch let error {
|
|
3019
|
+
print("Error creating JSON data: \(error)")
|
|
3020
|
+
hideLoadingIndicator()
|
|
3021
|
+
return
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
let session = URLSession.shared
|
|
3025
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
3026
|
+
|
|
3027
|
+
DispatchQueue.main.async {
|
|
3028
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
if let error = error {
|
|
3032
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
3033
|
+
return
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
3037
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
3038
|
+
return
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
3042
|
+
if let data = serviceData {
|
|
3043
|
+
do {
|
|
3044
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
3045
|
+
print("Response Data: \(responseObject)")
|
|
3046
|
+
|
|
3047
|
+
// Check if status is 0 and handle the error
|
|
3048
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
3049
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
3050
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
3051
|
+
} else {
|
|
3052
|
+
DispatchQueue.main.async {
|
|
3053
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
3054
|
+
paymentDoneVC.chargeData = responseObject
|
|
3055
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
3056
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
3057
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
} else {
|
|
3062
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
3063
|
+
}
|
|
3064
|
+
} catch let jsonError {
|
|
3065
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
3066
|
+
}
|
|
3067
|
+
} else {
|
|
3068
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
3069
|
+
}
|
|
3070
|
+
} else {
|
|
3071
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
task.resume()
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
//MARK: - Delete Bank Account Api.
|
|
3078
|
+
func deleteAccountApi(accountID: String, at index: Int) {
|
|
3079
|
+
showLoadingIndicator()
|
|
3080
|
+
|
|
3081
|
+
// var components = URLComponents()
|
|
3082
|
+
// components.scheme = "https"
|
|
3083
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
3084
|
+
// components.path = "/api/v1/ach/account/\(accountID)" // Append the account_id to the path
|
|
3085
|
+
//
|
|
3086
|
+
// guard let serviceURL = components.url else {
|
|
3087
|
+
// print("Invalid URL")
|
|
3088
|
+
// hideLoadingIndicator()
|
|
3089
|
+
// return
|
|
3090
|
+
// }
|
|
3091
|
+
|
|
3092
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
3093
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()+"/\(accountID)"
|
|
3094
|
+
|
|
3095
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
3096
|
+
print("Invalid URL")
|
|
3097
|
+
hideLoadingIndicator()
|
|
3098
|
+
return
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
var request = URLRequest(url: serviceURL)
|
|
3102
|
+
request.httpMethod = "DELETE"
|
|
3103
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
3104
|
+
|
|
3105
|
+
let token = UserStoreSingleton.shared.customerToken
|
|
3106
|
+
print("Setting customerToken header: \(token ?? "None")")
|
|
3107
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Customer-Token")
|
|
3108
|
+
|
|
3109
|
+
let session = URLSession.shared
|
|
3110
|
+
let task = session.dataTask(with: request) { [weak self] (serviceData, serviceResponse, error) in
|
|
3111
|
+
guard let self = self else { return }
|
|
3112
|
+
|
|
3113
|
+
DispatchQueue.main.async {
|
|
3114
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
if let error = error {
|
|
3118
|
+
DispatchQueue.main.async {
|
|
3119
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
3120
|
+
}
|
|
3121
|
+
return
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
3125
|
+
DispatchQueue.main.async {
|
|
3126
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
3127
|
+
}
|
|
3128
|
+
return
|
|
3129
|
+
}
|
|
3130
|
+
|
|
3131
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
3132
|
+
|
|
3133
|
+
if let data = serviceData {
|
|
3134
|
+
do {
|
|
3135
|
+
// Try to parse the data as JSON
|
|
3136
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
3137
|
+
let message = jsonResponse["message"] as? String {
|
|
3138
|
+
DispatchQueue.main.async {
|
|
3139
|
+
self.showToast(message: message)
|
|
3140
|
+
self.getShowBankAccountsApi()
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
} catch let jsonError {
|
|
3144
|
+
print("Error parsing JSON response: \(jsonError.localizedDescription)")
|
|
3145
|
+
}
|
|
3146
|
+
} else {
|
|
3147
|
+
print("No data received.")
|
|
3148
|
+
}
|
|
3149
|
+
} else {
|
|
3150
|
+
DispatchQueue.main.async {
|
|
3151
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
task.resume()
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// MARK: - Crypto Charge API
|
|
3159
|
+
func cryptoChargeApi() {
|
|
3160
|
+
showLoadingIndicator()
|
|
3161
|
+
// var components = URLComponents()
|
|
3162
|
+
// components.scheme = "https"
|
|
3163
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
3164
|
+
// components.path = "/api/v1/charges"
|
|
3165
|
+
//
|
|
3166
|
+
// guard let serviceURL = components.url else {
|
|
3167
|
+
// print("Invalid URL")
|
|
3168
|
+
// hideLoadingIndicator()
|
|
3169
|
+
// return
|
|
3170
|
+
// }
|
|
3171
|
+
|
|
3172
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
3173
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
3174
|
+
|
|
3175
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
3176
|
+
print("Invalid URL")
|
|
3177
|
+
hideLoadingIndicator()
|
|
3178
|
+
return
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
var request = URLRequest(url: serviceURL)
|
|
3182
|
+
request.httpMethod = "POST"
|
|
3183
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
3184
|
+
|
|
3185
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
3186
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
3187
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
3188
|
+
|
|
3189
|
+
let params: [String: Any] = [
|
|
3190
|
+
"name": UserStoreSingleton.shared.merchantName ?? "",
|
|
3191
|
+
"email": UserStoreSingleton.shared.merchantEmail ?? "",
|
|
3192
|
+
"description": "Payment checkout",
|
|
3193
|
+
"amount": amount ?? "",
|
|
3194
|
+
"currency": "satoshi",
|
|
3195
|
+
"payment_account": UserStoreSingleton.shared.paymentAccount ?? "",
|
|
3196
|
+
"success_url": "https://stage-api.stage-easymerchant.io/webhook/crypto",
|
|
3197
|
+
"callback_url": "https://stage-api.stage-easymerchant.io/webhook/crypto"
|
|
3198
|
+
]
|
|
3199
|
+
|
|
3200
|
+
print(params)
|
|
3201
|
+
|
|
3202
|
+
do {
|
|
3203
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
3204
|
+
request.httpBody = jsonData
|
|
3205
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
3206
|
+
print("JSON Payload: \(jsonString)")
|
|
3207
|
+
}
|
|
3208
|
+
} catch let error {
|
|
3209
|
+
print("Error creating JSON data: \(error)")
|
|
3210
|
+
hideLoadingIndicator()
|
|
3211
|
+
return
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
let session = URLSession.shared
|
|
3215
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
3216
|
+
|
|
3217
|
+
DispatchQueue.main.async {
|
|
3218
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3221
|
+
if let error = error {
|
|
3222
|
+
print("Error: \(error.localizedDescription)")
|
|
3223
|
+
return
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
3227
|
+
print("Invalid response")
|
|
3228
|
+
return
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
3232
|
+
if let data = serviceData {
|
|
3233
|
+
do {
|
|
3234
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
3235
|
+
print("Response Data: \(responseObject)")
|
|
3236
|
+
|
|
3237
|
+
// Check if status is 0 and handle the error
|
|
3238
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
3239
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
3240
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
3241
|
+
} else {
|
|
3242
|
+
// Extract charge_id
|
|
3243
|
+
if let chargeId = responseObject["charge_id"] as? String {
|
|
3244
|
+
self.chargeId = chargeId
|
|
3245
|
+
print("Charge ID: \(chargeId)")
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
// Extract chain_invoice address and lightning invoice fields
|
|
3249
|
+
if let data = responseObject["data"] as? [String: Any] {
|
|
3250
|
+
self.chainInvoiceAddress = (data["chain_invoice"] as? [String: Any])?["address"] as? String
|
|
3251
|
+
self.lightningURI = (data["lightning_invoice"] as? [String: Any])?["payreq"] as? String
|
|
3252
|
+
|
|
3253
|
+
// Default to OnChain QR code initially
|
|
3254
|
+
DispatchQueue.main.async {
|
|
3255
|
+
if let address = self.chainInvoiceAddress {
|
|
3256
|
+
self.qrImageView.image = self.generateQRCode(from: address)
|
|
3257
|
+
self.lblBTCAddress.text = "BTC Address: \(address)"
|
|
3258
|
+
|
|
3259
|
+
// Extract the amount from the URI
|
|
3260
|
+
if let uri = data["uri"] as? String {
|
|
3261
|
+
if let amountString = self.extractAmount(from: uri) {
|
|
3262
|
+
// Update the label with the extracted amount
|
|
3263
|
+
DispatchQueue.main.async {
|
|
3264
|
+
self.lblAmmoutCrypto.text = "\(amountString) BTC = $\(self.amount ?? 0) USD"
|
|
3265
|
+
self.lblCryptoAmmountViewTryAgain.text = "\(amountString) BTC = $\(self.amount ?? 0) USD"
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
self.viewCryptoQRCode.isHidden = false
|
|
3272
|
+
self.viewCryptoTryAgain.isHidden = true
|
|
3273
|
+
}
|
|
3274
|
+
} else {
|
|
3275
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response format")
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
} else {
|
|
3279
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
3280
|
+
}
|
|
3281
|
+
} catch let jsonError {
|
|
3282
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
3283
|
+
}
|
|
3284
|
+
} else {
|
|
3285
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
3286
|
+
}
|
|
3287
|
+
} else {
|
|
3288
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
task.resume()
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
// Helper function to extract the amount from the URI
|
|
3295
|
+
func extractAmount(from uri: String) -> String? {
|
|
3296
|
+
let regex = try? NSRegularExpression(pattern: "amount=([\\d.]+)", options: [])
|
|
3297
|
+
let matches = regex?.matches(in: uri, options: [], range: NSRange(location: 0, length: uri.count))
|
|
3298
|
+
|
|
3299
|
+
if let match = matches?.first, let amountRange = Range(match.range(at: 1), in: uri) {
|
|
3300
|
+
return String(uri[amountRange])
|
|
3301
|
+
}
|
|
3302
|
+
return nil
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
//MARK: - GET Crypto Payment Info API
|
|
3306
|
+
func getCryptoPaymentInfoApi(chargeId: String) {
|
|
3307
|
+
|
|
3308
|
+
// var components = URLComponents()
|
|
3309
|
+
// components.scheme = "https"
|
|
3310
|
+
// components.host = "stage-api.stage-easymerchant.io"
|
|
3311
|
+
// components.path = "/api/v1/charges/\(chargeId)" // Append chargeId to the path
|
|
3312
|
+
//
|
|
3313
|
+
// guard let serviceURL = components.url else {
|
|
3314
|
+
// print("Invalid URL")
|
|
3315
|
+
// return
|
|
3316
|
+
// }
|
|
3317
|
+
|
|
3318
|
+
// Construct the full URL using baseURL from EnvironmentConfig and path from the endpoint
|
|
3319
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()+"/\(chargeId)"
|
|
3320
|
+
|
|
3321
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
3322
|
+
print("Invalid URL")
|
|
3323
|
+
hideLoadingIndicator()
|
|
3324
|
+
return
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
var request = URLRequest(url: serviceURL)
|
|
3328
|
+
request.httpMethod = "GET"
|
|
3329
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
3330
|
+
|
|
3331
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
3332
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
3333
|
+
request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
3334
|
+
|
|
3335
|
+
let session = URLSession.shared
|
|
3336
|
+
let task = session.dataTask(with: request) { [weak self] (data, response, error) in
|
|
3337
|
+
guard let self = self else { return }
|
|
3338
|
+
|
|
3339
|
+
if let error = error {
|
|
3340
|
+
print("Error: \(error.localizedDescription)")
|
|
3341
|
+
return
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
guard let data = data else { return }
|
|
3345
|
+
|
|
3346
|
+
do {
|
|
3347
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
3348
|
+
let responseData = jsonResponse["data"] as? [String: Any] {
|
|
3349
|
+
|
|
3350
|
+
// Extract required data
|
|
3351
|
+
let amount = responseData["amount"] as? String ?? ""
|
|
3352
|
+
let dateCreated = responseData["date_created"] as? String ?? ""
|
|
3353
|
+
let status = responseData["status"] as? String ?? ""
|
|
3354
|
+
let transactionId = responseData["transaction_id"] as? String ?? ""
|
|
3355
|
+
|
|
3356
|
+
print("Amount: \(amount), Date Created: \(dateCreated), Status: \(status), Transaction ID: \(transactionId)")
|
|
3357
|
+
|
|
3358
|
+
// Check if the status is "completed"
|
|
3359
|
+
if status.lowercased() == "completed" {
|
|
3360
|
+
DispatchQueue.main.async {
|
|
3361
|
+
// Navigate to PaymentDoneVC and pass data
|
|
3362
|
+
self.navigateToPaymentDoneVC(amount: amount, dateCreated: dateCreated, transactionId: transactionId)
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
} catch {
|
|
3367
|
+
print("Failed to parse response: \(error.localizedDescription)")
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
task.resume()
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
//MARK: - Navigation to PaymentDoneVC
|
|
3374
|
+
func navigateToPaymentDoneVC(amount: String, dateCreated: String, transactionId: String) {
|
|
3375
|
+
if let paymentDoneVC = storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
3376
|
+
// Set the properties of PaymentDoneVC with the extracted data
|
|
3377
|
+
paymentDoneVC.amount = amount
|
|
3378
|
+
paymentDoneVC.dateCreated = dateCreated
|
|
3379
|
+
paymentDoneVC.transactionId = transactionId
|
|
3380
|
+
paymentDoneVC.isFrom = "Crypto"
|
|
3381
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
//MARK: - Collection View.
|
|
3388
|
+
extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
|
3389
|
+
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
3390
|
+
return arrPaymentMethods.count
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
3394
|
+
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PaymentInformationCVC", for: indexPath) as! PaymentInformationCVC
|
|
3395
|
+
cell.setUI()
|
|
3396
|
+
cell.imgVwPayments.image = UIImage.init(systemName: arrPaymentMethods[indexPath.row].image)
|
|
3397
|
+
cell.lblPayment.text = arrPaymentMethods[indexPath.row].name
|
|
3398
|
+
|
|
3399
|
+
// Update border color based on selection
|
|
3400
|
+
if selectedIndex == indexPath {
|
|
3401
|
+
cell.vwMain.layer.borderColor = UIColor.systemBlue.cgColor
|
|
3402
|
+
cell.imgVwPayments.tintColor = .systemBlue
|
|
3403
|
+
cell.lblPayment.textColor = .systemBlue
|
|
3404
|
+
} else {
|
|
3405
|
+
cell.vwMain.layer.borderColor = UIColor.gray.cgColor
|
|
3406
|
+
cell.imgVwPayments.tintColor = .systemGray
|
|
3407
|
+
cell.lblPayment.textColor = .systemGray
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
return cell
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
|
3414
|
+
selectedIndex = indexPath
|
|
3415
|
+
selectedPaymentMethod = arrPaymentMethods[indexPath.row].name
|
|
3416
|
+
collectionView.reloadData()
|
|
3417
|
+
|
|
3418
|
+
// Show the appropriate view based on the selected payment method
|
|
3419
|
+
switch arrPaymentMethods[indexPath.row].name {
|
|
3420
|
+
case "Card":
|
|
3421
|
+
if selectedPaymentMethod == "Card" {
|
|
3422
|
+
if UserStoreSingleton.shared.isLoggedIn == false {
|
|
3423
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
3424
|
+
self.viewBankFields.isHidden = true
|
|
3425
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
3426
|
+
self.lblBtnShowSaveCard.text = "Show Saved Cards"
|
|
3427
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
3428
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
3429
|
+
self.OTPView.isHidden = true
|
|
3430
|
+
self.emailView.isHidden = true
|
|
3431
|
+
self.viewCardFields.isHidden = false
|
|
3432
|
+
self.viewSingleSavedCard.isHidden = true
|
|
3433
|
+
self.viewChangeCard.isHidden = true
|
|
3434
|
+
self.viewUpdateCard.isHidden = true
|
|
3435
|
+
self.viewAddNewCard.isHidden = true
|
|
3436
|
+
self.btnNext.isHidden = false
|
|
3437
|
+
self.btnNextHeight.constant = 50
|
|
3438
|
+
self.btnNextTopCon.constant = 20
|
|
3439
|
+
self.viewTermsAndConditions.isHidden = true
|
|
3440
|
+
self.viewCrypto.isHidden = true
|
|
3441
|
+
}
|
|
3442
|
+
else {
|
|
3443
|
+
getShowCardsApi()
|
|
3444
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
3445
|
+
self.viewBankFields.isHidden = true
|
|
3446
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
3447
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
3448
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
3449
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
3450
|
+
self.OTPView.isHidden = true
|
|
3451
|
+
self.emailView.isHidden = true
|
|
3452
|
+
self.viewCardFields.isHidden = true
|
|
3453
|
+
self.viewSingleSavedCard.isHidden = false
|
|
3454
|
+
self.viewChangeCard.isHidden = true
|
|
3455
|
+
self.viewUpdateCard.isHidden = true
|
|
3456
|
+
self.viewAddNewCard.isHidden = true
|
|
3457
|
+
self.btnNext.isHidden = true
|
|
3458
|
+
self.btnNextHeight.constant = 0
|
|
3459
|
+
self.btnNextTopCon.constant = 8
|
|
3460
|
+
self.viewChangedAccount.isHidden = true
|
|
3461
|
+
self.viewNewBankAccount.isHidden = true
|
|
3462
|
+
self.viewCrypto.isHidden = true
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
case "Bank":
|
|
3466
|
+
if selectedPaymentMethod == "Bank" {
|
|
3467
|
+
if UserStoreSingleton.shared.isLoggedIn == false {
|
|
3468
|
+
self.viewBankFields.isHidden = false
|
|
3469
|
+
self.viewBtnShowSavedCards.isHidden = false
|
|
3470
|
+
self.lblBtnShowSaveCard.text = "Use Saved Accounts"
|
|
3471
|
+
self.viewBtnShowSavedCardHeight.constant = 50
|
|
3472
|
+
self.viewBtnShowSavedCardTopCon.constant = 20
|
|
3473
|
+
self.OTPView.isHidden = true
|
|
3474
|
+
self.emailView.isHidden = true
|
|
3475
|
+
self.viewCardFields.isHidden = true
|
|
3476
|
+
self.viewSingleSavedCard.isHidden = true
|
|
3477
|
+
self.viewChangeCard.isHidden = true
|
|
3478
|
+
self.viewUpdateCard.isHidden = true
|
|
3479
|
+
self.viewAddNewCard.isHidden = true
|
|
3480
|
+
self.btnNext.isHidden = false
|
|
3481
|
+
self.btnNextHeight.constant = 50
|
|
3482
|
+
self.btnNextTopCon.constant = 20
|
|
3483
|
+
self.viewTermsAndConditions.isHidden = false
|
|
3484
|
+
self.viewCrypto.isHidden = true
|
|
3485
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
3486
|
+
}
|
|
3487
|
+
else {
|
|
3488
|
+
getShowBankAccountsApi()
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
case "Crypto":
|
|
3492
|
+
if selectedPaymentMethod == "Crypto" {
|
|
3493
|
+
self.cryptoChargeApi()
|
|
3494
|
+
self.startCryptoTimer()
|
|
3495
|
+
self.totalTimeInSeconds = 300
|
|
3496
|
+
|
|
3497
|
+
self.viewCrypto.isHidden = false
|
|
3498
|
+
self.viewQrCodeHeight.constant = 440
|
|
3499
|
+
self.viewCryptoHeight.constant = 440
|
|
3500
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
3501
|
+
self.viewBankFields.isHidden = true
|
|
3502
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
3503
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
3504
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
3505
|
+
self.OTPView.isHidden = true
|
|
3506
|
+
self.emailView.isHidden = true
|
|
3507
|
+
self.viewCardFields.isHidden = true
|
|
3508
|
+
self.viewSingleSavedCard.isHidden = true
|
|
3509
|
+
self.viewChangeCard.isHidden = true
|
|
3510
|
+
self.viewUpdateCard.isHidden = true
|
|
3511
|
+
self.viewAddNewCard.isHidden = true
|
|
3512
|
+
self.btnNext.isHidden = true
|
|
3513
|
+
self.btnNextHeight.constant = 0
|
|
3514
|
+
self.btnNextTopCon.constant = 8
|
|
3515
|
+
self.viewTermsAndConditions.isHidden = true
|
|
3516
|
+
self.viewChangedAccount.isHidden = true
|
|
3517
|
+
self.viewNewBankAccount.isHidden = true
|
|
3518
|
+
|
|
3519
|
+
}
|
|
3520
|
+
default:
|
|
3521
|
+
break
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
|
3526
|
+
return CGSize(width: 100, height: 70)
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
//MARK: - Table View
|
|
3532
|
+
extension PaymentInfoVC: UITableViewDelegate, UITableViewDataSource {
|
|
3533
|
+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
3534
|
+
if tableView == tblViewSavedCardsList {
|
|
3535
|
+
return savedCards.count + 1
|
|
3536
|
+
}
|
|
3537
|
+
else if tableView == tblViewSavedBankAccounts {
|
|
3538
|
+
return bankAccounts.count + 1
|
|
3539
|
+
}
|
|
3540
|
+
else if tableView == tblViewAccountTypes {
|
|
3541
|
+
return arrAccountType.count
|
|
3542
|
+
}
|
|
3543
|
+
else if tableView == tblViewAccountTypeNewAccountView {
|
|
3544
|
+
return arrAccountType.count
|
|
3545
|
+
}
|
|
3546
|
+
return 0
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
3550
|
+
if tableView == tblViewSavedCardsList {
|
|
3551
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "SavedCardsTVC", for: indexPath) as! SavedCardsTVC
|
|
3552
|
+
// Clear previous button targets to avoid duplicate actions
|
|
3553
|
+
cell.btnSelectCard.removeTarget(nil, action: nil, for: .allEvents)
|
|
3554
|
+
cell.btnThreeDot.removeTarget(nil, action: nil, for: .allEvents)
|
|
3555
|
+
cell.btnRemoveCard.removeTarget(nil, action: nil, for: .allEvents)
|
|
3556
|
+
cell.btnUpdateCard.removeTarget(nil, action: nil, for: .allEvents)
|
|
3557
|
+
|
|
3558
|
+
// Check if it's the "Add New Card" cell
|
|
3559
|
+
if indexPath.row == savedCards.count {
|
|
3560
|
+
configureAddNewCardCell(cell)
|
|
3561
|
+
} else {
|
|
3562
|
+
configureSavedCardCell(cell, at: indexPath)
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
return cell
|
|
3566
|
+
}
|
|
3567
|
+
else if tableView == tblViewSavedBankAccounts {
|
|
3568
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "SavedAccountTVC", for: indexPath) as! SavedAccountTVC
|
|
3569
|
+
// Clear previous button targets to avoid duplicate actions
|
|
3570
|
+
cell.btnSelectAccount.removeTarget(nil, action: nil, for: .allEvents)
|
|
3571
|
+
cell.btnThreeDotBank.removeTarget(nil, action: nil, for: .allEvents)
|
|
3572
|
+
cell.btnRemoveBankAccount.removeTarget(nil, action: nil, for: .allEvents)
|
|
3573
|
+
|
|
3574
|
+
// Check if it's the "Add New Card" cell
|
|
3575
|
+
if indexPath.row == bankAccounts.count {
|
|
3576
|
+
configureAddNewAccountCell(cell)
|
|
3577
|
+
} else {
|
|
3578
|
+
configureSavedAccountCell(cell, at: indexPath)
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
return cell
|
|
3582
|
+
}
|
|
3583
|
+
else if tableView == tblViewAccountTypes {
|
|
3584
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "AccountTypeTVC") as! AccountTypeTVC
|
|
3585
|
+
cell.lblAccountType.text = arrAccountType[indexPath.row]
|
|
3586
|
+
return cell
|
|
3587
|
+
}
|
|
3588
|
+
else if tableView == tblViewAccountTypeNewAccountView {
|
|
3589
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "AccountTypeTVC") as! AccountTypeTVC
|
|
3590
|
+
cell.lblAccountType.text = arrAccountType[indexPath.row]
|
|
3591
|
+
return cell
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
return UITableViewCell()
|
|
3595
|
+
}
|
|
3596
|
+
|
|
3597
|
+
//Card
|
|
3598
|
+
func configureAddNewCardCell(_ cell: SavedCardsTVC) {
|
|
3599
|
+
cell.lblCardNumber.text = "New Card"
|
|
3600
|
+
cell.lblExpireDate.isHidden = true
|
|
3601
|
+
cell.btnThreeDot.isHidden = true
|
|
3602
|
+
cell.imgViewCard.isHidden = true
|
|
3603
|
+
cell.btnSelectCard.setImage(UIImage(systemName: "plus"), for: .normal)
|
|
3604
|
+
cell.btnSelectCard.tag = savedCards.count
|
|
3605
|
+
cell.btnSelectCard.addTarget(self, action: #selector(addNewCardTapped(_:)), for: .touchUpInside)
|
|
3606
|
+
cell.viewBtnRemoveUpdate.isHidden = true
|
|
3607
|
+
|
|
3608
|
+
cell.imgViewCardWidth.constant = 0
|
|
3609
|
+
cell.imgViewCardRightCon.constant = 0
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
func configureSavedCardCell(_ cell: SavedCardsTVC, at indexPath: IndexPath) {
|
|
3613
|
+
let card = savedCards[indexPath.row]
|
|
3614
|
+
cell.lblCardNumber.text = "****\(card.ccLast4)"
|
|
3615
|
+
cell.lblExpireDate.isHidden = false
|
|
3616
|
+
cell.lblExpireDate.text = "Expiry: \(card.ccValidThru)"
|
|
3617
|
+
cell.btnThreeDot.isHidden = false
|
|
3618
|
+
cell.imgViewCard.isHidden = false
|
|
3619
|
+
|
|
3620
|
+
// Reset constraints for regular saved card cells
|
|
3621
|
+
cell.imgViewCardWidth.constant = 40 // Set to the original width constraint value
|
|
3622
|
+
cell.imgViewCardRightCon.constant = 16 // Set to the original right constraint value
|
|
3623
|
+
|
|
3624
|
+
// Update button image based on the selected state
|
|
3625
|
+
let isSelected = (selectedCardIndex == indexPath.row)
|
|
3626
|
+
let imageName = isSelected ? "circle.inset.filled" : "circle"
|
|
3627
|
+
cell.btnSelectCard.setImage(UIImage(systemName: imageName), for: .normal)
|
|
3628
|
+
|
|
3629
|
+
// Set up actions for buttons
|
|
3630
|
+
cell.btnSelectCard.tag = indexPath.row
|
|
3631
|
+
cell.btnSelectCard.addTarget(self, action: #selector(btnSelectCardTapped(_:)), for: .touchUpInside)
|
|
3632
|
+
|
|
3633
|
+
cell.btnThreeDot.tag = indexPath.row
|
|
3634
|
+
cell.btnThreeDot.addTarget(self, action: #selector(btnThreeDotTapped(_:)), for: .touchUpInside)
|
|
3635
|
+
|
|
3636
|
+
cell.btnRemoveCard.tag = indexPath.row
|
|
3637
|
+
cell.btnRemoveCard.addTarget(self, action: #selector(btnRemoveCardTapped(_:)), for: .touchUpInside)
|
|
3638
|
+
|
|
3639
|
+
cell.btnUpdateCard.tag = indexPath.row
|
|
3640
|
+
cell.btnUpdateCard.addTarget(self, action: #selector(btnUpdateCardTapped(_:)), for: .touchUpInside)
|
|
3641
|
+
|
|
3642
|
+
// Hide or show the remove/update view based on cell state
|
|
3643
|
+
cell.viewBtnRemoveUpdate.isHidden = !cell.isRemoveUpdateViewVisible
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3646
|
+
//Bank
|
|
3647
|
+
func configureAddNewAccountCell(_ cell: SavedAccountTVC) {
|
|
3648
|
+
cell.lblAccountNumber.text = "New Account"
|
|
3649
|
+
cell.lblAccountType.isHidden = true
|
|
3650
|
+
cell.btnThreeDotBank.isHidden = true
|
|
3651
|
+
cell.imgViewBank.isHidden = true
|
|
3652
|
+
cell.btnSelectAccount.setImage(UIImage(systemName: "plus"), for: .normal)
|
|
3653
|
+
cell.btnSelectAccount.tag = bankAccounts.count
|
|
3654
|
+
cell.btnSelectAccount.addTarget(self, action: #selector(addNewBankAccountTapped(_:)), for: .touchUpInside)
|
|
3655
|
+
cell.viewBtnRemove.isHidden = true
|
|
3656
|
+
|
|
3657
|
+
cell.imgViewBankWidth.constant = 0
|
|
3658
|
+
cell.imgViewBankRightCon.constant = 0
|
|
3659
|
+
}
|
|
3660
|
+
|
|
3661
|
+
func configureSavedAccountCell(_ cell: SavedAccountTVC, at indexPath: IndexPath) {
|
|
3662
|
+
let bank = bankAccounts[indexPath.row]
|
|
3663
|
+
cell.lblAccountNumber.text = "****\(bank.account_number_last_4 ?? "")"
|
|
3664
|
+
cell.lblAccountType.isHidden = false
|
|
3665
|
+
cell.lblAccountType.text = "Type: \(bank.account_type ?? "")"
|
|
3666
|
+
cell.btnThreeDotBank.isHidden = false
|
|
3667
|
+
cell.imgViewBank.isHidden = false
|
|
3668
|
+
|
|
3669
|
+
// Reset constraints for regular saved card cells
|
|
3670
|
+
cell.imgViewBankWidth.constant = 40 // Set to the original width constraint value
|
|
3671
|
+
cell.imgViewBankRightCon.constant = 16 // Set to the original right constraint value
|
|
3672
|
+
|
|
3673
|
+
// Update button image based on the selected state
|
|
3674
|
+
let isSelected = (selectedBankIndex == indexPath.row)
|
|
3675
|
+
let imageName = isSelected ? "circle.inset.filled" : "circle"
|
|
3676
|
+
cell.btnSelectAccount.setImage(UIImage(systemName: imageName), for: .normal)
|
|
3677
|
+
|
|
3678
|
+
// Set up actions for buttons
|
|
3679
|
+
cell.btnSelectAccount.tag = indexPath.row
|
|
3680
|
+
cell.btnSelectAccount.addTarget(self, action: #selector(btnSelectAccountTapped(_:)), for: .touchUpInside)
|
|
3681
|
+
|
|
3682
|
+
cell.btnThreeDotBank.tag = indexPath.row
|
|
3683
|
+
cell.btnThreeDotBank.addTarget(self, action: #selector(btnThreeDotBankTapped(_:)), for: .touchUpInside)
|
|
3684
|
+
|
|
3685
|
+
cell.btnRemoveBankAccount.tag = indexPath.row
|
|
3686
|
+
cell.btnRemoveBankAccount.addTarget(self, action: #selector(btnRemoveBankAccountTapped(_:)), for: .touchUpInside)
|
|
3687
|
+
|
|
3688
|
+
// Hide or show the remove/update view based on cell state
|
|
3689
|
+
cell.viewBtnRemove.isHidden = !cell.isRemoveUpdateViewVisible
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
3693
|
+
if tableView == tblViewAccountTypes {
|
|
3694
|
+
return 45
|
|
3695
|
+
}
|
|
3696
|
+
else if tableView == tblViewAccountTypeNewAccountView {
|
|
3697
|
+
return 45
|
|
3698
|
+
}
|
|
3699
|
+
else {
|
|
3700
|
+
return 80
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
|
|
3704
|
+
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
3705
|
+
if tableView == tblViewAccountTypes {
|
|
3706
|
+
let selectedAccountType = arrAccountType[indexPath.row]
|
|
3707
|
+
txtFieldAccountType.text = selectedAccountType // Fill the selected account type into the text field
|
|
3708
|
+
viewAccountType.isHidden = true // Hide the table view after selection
|
|
3709
|
+
}
|
|
3710
|
+
else if tableView == tblViewAccountTypeNewAccountView {
|
|
3711
|
+
let selectedAccountType = arrAccountType[indexPath.row]
|
|
3712
|
+
txtFieldAccountTypeNewAccountView.text = selectedAccountType // Fill the selected account type into the text field
|
|
3713
|
+
viewAccountTypeNewAccountView.isHidden = true // Hide the table view after selection
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
@objc func btnSelectCardTapped(_ sender: UIButton) {
|
|
3718
|
+
let index = sender.tag
|
|
3719
|
+
|
|
3720
|
+
// Store the index of the previously selected card
|
|
3721
|
+
let previousSelectedIndex = selectedCardIndex
|
|
3722
|
+
|
|
3723
|
+
// Toggle the selection state: if the same card is selected, deselect it; otherwise, select the new one
|
|
3724
|
+
selectedCardIndex = (selectedCardIndex == index) ? nil : index
|
|
3725
|
+
|
|
3726
|
+
// Update the single card view
|
|
3727
|
+
if let selectedIndex = selectedCardIndex {
|
|
3728
|
+
updateSingleCardView(for: selectedIndex)
|
|
3729
|
+
viewSingleSavedCard.isHidden = false
|
|
3730
|
+
viewChangeCard.isHidden = true
|
|
3731
|
+
} else {
|
|
3732
|
+
viewSingleSavedCard.isHidden = true
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
// Reload the previously selected row to update its state
|
|
3736
|
+
if let previousIndex = previousSelectedIndex {
|
|
3737
|
+
tblViewSavedCardsList.reloadRows(at: [IndexPath(row: previousIndex, section: 0)], with: .automatic)
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
// Reload the newly selected row to update its state
|
|
3741
|
+
tblViewSavedCardsList.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
|
|
3742
|
+
}
|
|
3743
|
+
|
|
3744
|
+
private func updateSingleCardView(for index: Int) {
|
|
3745
|
+
let selectedCard = savedCards[index]
|
|
3746
|
+
lblCardNumberSigleSavedCard.text = "****\(selectedCard.ccLast4)"
|
|
3747
|
+
lblExpireDateSingelSavedCard.text = "Expiry: \(selectedCard.ccValidThru)"
|
|
3748
|
+
|
|
3749
|
+
if isSelectForPay {
|
|
3750
|
+
viewTxtFieldCVVSingleCard.isHidden = false
|
|
3751
|
+
btnPayNowSingleCard.isHidden = false
|
|
3752
|
+
viewSingleSavedCardHeight.constant = 220
|
|
3753
|
+
} else {
|
|
3754
|
+
viewTxtFieldCVVSingleCard.isHidden = true
|
|
3755
|
+
btnPayNowSingleCard.isHidden = true
|
|
3756
|
+
viewSingleSavedCardHeight.constant = 60
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
|
|
3760
|
+
@objc func btnThreeDotTapped(_ sender: UIButton) {
|
|
3761
|
+
let index = sender.tag
|
|
3762
|
+
guard let cell = tblViewSavedCardsList.cellForRow(at: IndexPath(row: index, section: 0)) as? SavedCardsTVC else {
|
|
3763
|
+
return
|
|
3764
|
+
}
|
|
3765
|
+
// Toggle visibility of remove/update buttons
|
|
3766
|
+
cell.isRemoveUpdateViewVisible.toggle()
|
|
3767
|
+
cell.viewBtnRemoveUpdate.isHidden = !cell.isRemoveUpdateViewVisible
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
@objc func btnRemoveCardTapped(_ sender: UIButton) {
|
|
3771
|
+
let index = sender.tag
|
|
3772
|
+
|
|
3773
|
+
let selectedCard = savedCards[index]
|
|
3774
|
+
selectedCardID = selectedCard.cardId
|
|
3775
|
+
|
|
3776
|
+
let alertController = UIAlertController(
|
|
3777
|
+
title: "Confirm Deletion",
|
|
3778
|
+
message: "Are you sure you want to delete this card?",
|
|
3779
|
+
preferredStyle: .alert
|
|
3780
|
+
)
|
|
3781
|
+
let noAction = UIAlertAction(title: "No", style: .cancel, handler: nil)
|
|
3782
|
+
let yesAction = UIAlertAction(title: "Yes", style: .destructive) { [weak self] _ in
|
|
3783
|
+
guard let self = self else { return }
|
|
3784
|
+
// Call the deleteCardApi with the selected card ID
|
|
3785
|
+
self.deleteCardApi(cardID: selectedCard.cardId, at: index)
|
|
3786
|
+
}
|
|
3787
|
+
alertController.addAction(noAction)
|
|
3788
|
+
alertController.addAction(yesAction)
|
|
3789
|
+
present(alertController, animated: true, completion: nil)
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3792
|
+
@objc func btnUpdateCardTapped(_ sender: UIButton) {
|
|
3793
|
+
let index = sender.tag
|
|
3794
|
+
let selectedCard = savedCards[index]
|
|
3795
|
+
lblCardNumberUpdateCardView.text = "****\(selectedCard.ccLast4)"
|
|
3796
|
+
lblExpireDateUpdateCardView.text = "Expiry: \(selectedCard.ccValidThru)"
|
|
3797
|
+
|
|
3798
|
+
selectedCardID = selectedCard.cardId
|
|
3799
|
+
|
|
3800
|
+
viewUpdateCard.isHidden = false
|
|
3801
|
+
// Adjust view visibility
|
|
3802
|
+
viewBtnShowSavedCards.isHidden = true
|
|
3803
|
+
viewBtnShowSavedCardHeight.constant = 0
|
|
3804
|
+
viewBtnShowSavedCardTopCon.constant = 0
|
|
3805
|
+
viewCardFields.isHidden = true
|
|
3806
|
+
btnNext.isHidden = true
|
|
3807
|
+
btnNextHeight.constant = 0
|
|
3808
|
+
btnNextTopCon.constant = 8
|
|
3809
|
+
viewChangeCard.isHidden = true
|
|
3810
|
+
viewAddNewCard.isHidden = true
|
|
3811
|
+
viewSingleSavedCard.isHidden = true
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3814
|
+
@objc func addNewCardTapped(_ sender: UIButton) {
|
|
3815
|
+
// Make the Add New Card view visible
|
|
3816
|
+
viewAddNewCard.isHidden = false
|
|
3817
|
+
|
|
3818
|
+
// Hide other conflicting views to prevent UI overlap
|
|
3819
|
+
viewSingleSavedCard.isHidden = true
|
|
3820
|
+
viewChangeCard.isHidden = true
|
|
3821
|
+
viewUpdateCard.isHidden = true
|
|
3822
|
+
viewCardFields.isHidden = true
|
|
3823
|
+
|
|
3824
|
+
// Adjust visibility of any other related views if necessary
|
|
3825
|
+
viewBtnShowSavedCards.isHidden = true
|
|
3826
|
+
viewBtnShowSavedCardHeight.constant = 0
|
|
3827
|
+
viewBtnShowSavedCardTopCon.constant = 0
|
|
3828
|
+
btnNext.isHidden = true
|
|
3829
|
+
btnNextHeight.constant = 0
|
|
3830
|
+
btnNextTopCon.constant = 8
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
//Bank Cell
|
|
3834
|
+
@objc func addNewBankAccountTapped(_ sender: UIButton) {
|
|
3835
|
+
self.viewNewBankAccount.isHidden = false
|
|
3836
|
+
self.viewSingleSavedAccount.isHidden = true
|
|
3837
|
+
self.viewBankFields.isHidden = true
|
|
3838
|
+
self.viewBtnShowSavedCards.isHidden = true
|
|
3839
|
+
self.viewBtnShowSavedCardHeight.constant = 0
|
|
3840
|
+
self.viewBtnShowSavedCardTopCon.constant = 0
|
|
3841
|
+
self.OTPView.isHidden = true
|
|
3842
|
+
self.emailView.isHidden = true
|
|
3843
|
+
self.viewCardFields.isHidden = true
|
|
3844
|
+
self.viewSingleSavedCard.isHidden = true
|
|
3845
|
+
self.viewChangeCard.isHidden = true
|
|
3846
|
+
self.viewUpdateCard.isHidden = true
|
|
3847
|
+
self.viewAddNewCard.isHidden = true
|
|
3848
|
+
self.btnNext.isHidden = true
|
|
3849
|
+
self.btnNextHeight.constant = 0
|
|
3850
|
+
self.btnNextTopCon.constant = 8
|
|
3851
|
+
self.viewChangedAccount.isHidden = true
|
|
3852
|
+
}
|
|
3853
|
+
|
|
3854
|
+
@objc func btnSelectAccountTapped(_ sender: UIButton) {
|
|
3855
|
+
let index = sender.tag
|
|
3856
|
+
// Store the index of the previously selected card
|
|
3857
|
+
let previousSelectedIndex = selectedBankIndex
|
|
3858
|
+
|
|
3859
|
+
// Toggle the selection state: if the same card is selected, deselect it; otherwise, select the new one
|
|
3860
|
+
selectedBankIndex = (selectedBankIndex == index) ? nil : index
|
|
3861
|
+
|
|
3862
|
+
// Update the single card view
|
|
3863
|
+
if let selectedIndex = selectedBankIndex {
|
|
3864
|
+
updateSingleBankView(for: selectedIndex)
|
|
3865
|
+
viewSingleSavedAccount.isHidden = false
|
|
3866
|
+
viewChangedAccount.isHidden = true
|
|
3867
|
+
} else {
|
|
3868
|
+
viewSingleSavedAccount.isHidden = true
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
// Reload the previously selected row to update its state
|
|
3872
|
+
if let previousIndex = previousSelectedIndex {
|
|
3873
|
+
tblViewSavedBankAccounts.reloadRows(at: [IndexPath(row: previousIndex, section: 0)], with: .automatic)
|
|
3874
|
+
}
|
|
3875
|
+
|
|
3876
|
+
// Reload the newly selected row to update its state
|
|
3877
|
+
tblViewSavedBankAccounts.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
private func updateSingleBankView(for index: Int) {
|
|
3881
|
+
let selectedCard = bankAccounts[index]
|
|
3882
|
+
lblAccountNumberSingleAccountView.text = "****\(selectedCard.account_number_last_4 ?? "")"
|
|
3883
|
+
lblAccountTypeSingleAccountView.text = "Type: \(selectedCard.account_type ?? "")"
|
|
3884
|
+
|
|
3885
|
+
if isSelectForPayBank {
|
|
3886
|
+
viewTermAndConditionsSingleAccountView.isHidden = false
|
|
3887
|
+
btnPayNowSingleAccountView.isHidden = false
|
|
3888
|
+
viewSingleAccountViewHeight.constant = 170
|
|
3889
|
+
} else {
|
|
3890
|
+
viewTermAndConditionsSingleAccountView.isHidden = true
|
|
3891
|
+
btnPayNowSingleAccountView.isHidden = true
|
|
3892
|
+
viewSingleAccountViewHeight.constant = 68
|
|
3893
|
+
btnNext.isHidden = true
|
|
3894
|
+
btnNextHeight.constant = 0
|
|
3895
|
+
btnNextTopCon.constant = 0
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
|
|
3899
|
+
@objc func btnThreeDotBankTapped(_ sender: UIButton) {
|
|
3900
|
+
let index = sender.tag
|
|
3901
|
+
guard let cell = tblViewSavedBankAccounts.cellForRow(at: IndexPath(row: index, section: 0)) as? SavedAccountTVC else {
|
|
3902
|
+
return
|
|
3903
|
+
}
|
|
3904
|
+
// Toggle visibility of remove/update buttons
|
|
3905
|
+
cell.isRemoveUpdateViewVisible.toggle()
|
|
3906
|
+
cell.viewBtnRemove.isHidden = !cell.isRemoveUpdateViewVisible
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3909
|
+
@objc func btnRemoveBankAccountTapped(_ sender: UIButton) {
|
|
3910
|
+
let index = sender.tag
|
|
3911
|
+
|
|
3912
|
+
let selectedAccount = bankAccounts[index]
|
|
3913
|
+
selectedBankID = selectedAccount.account_id
|
|
3914
|
+
|
|
3915
|
+
let alertController = UIAlertController(
|
|
3916
|
+
title: "Confirm Deletion",
|
|
3917
|
+
message: "Are you sure you want to delete this account?",
|
|
3918
|
+
preferredStyle: .alert
|
|
3919
|
+
)
|
|
3920
|
+
let noAction = UIAlertAction(title: "No", style: .cancel, handler: nil)
|
|
3921
|
+
let yesAction = UIAlertAction(title: "Yes", style: .destructive) { [weak self] _ in
|
|
3922
|
+
guard let self = self else { return }
|
|
3923
|
+
// Call the deleteCardApi with the selected card ID
|
|
3924
|
+
self.deleteAccountApi(accountID: selectedAccount.account_id ?? "", at: index)
|
|
3925
|
+
}
|
|
3926
|
+
alertController.addAction(noAction)
|
|
3927
|
+
alertController.addAction(yesAction)
|
|
3928
|
+
present(alertController, animated: true, completion: nil)
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
}
|
|
3932
|
+
|
|
3933
|
+
// MARK: - Text Field Delegate Methods
|
|
3934
|
+
extension PaymentInfoVC: UITextFieldDelegate {
|
|
3935
|
+
|
|
3936
|
+
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
3937
|
+
if textField == txtFieldEmail {
|
|
3938
|
+
// Check if the email field is empty
|
|
3939
|
+
guard let email = textField.text, !email.isEmpty else {
|
|
3940
|
+
// Show an alert if the email field is empty
|
|
3941
|
+
showAlert(message: "Please enter an email address.")
|
|
3942
|
+
return false
|
|
3943
|
+
}
|
|
3944
|
+
// Validate email format before calling the API
|
|
3945
|
+
if isValidEmail(email) {
|
|
3946
|
+
// Hide email view, show OTP view, and start the timer
|
|
3947
|
+
emailView.isHidden = true
|
|
3948
|
+
OTPView.isHidden = false
|
|
3949
|
+
startTimer()
|
|
3950
|
+
// Call the email verification API
|
|
3951
|
+
emailVerificationApi()
|
|
3952
|
+
} else {
|
|
3953
|
+
// Show an alert or error message if the email is not valid
|
|
3954
|
+
showAlert(message: "Please enter a valid email address.")
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
textField.resignFirstResponder()
|
|
3958
|
+
return true
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
func textFieldDidChangeSelection(_ textField: UITextField) {
|
|
3962
|
+
guard let otpCode = textField.text, otpCode.count >= 6, textField.textContentType == .oneTimeCode else { return }
|
|
3963
|
+
txtFieldOTPText1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
|
|
3964
|
+
txtFieldOTPText2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
|
|
3965
|
+
txtFieldOTPText3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
|
|
3966
|
+
txtFieldOTPText4.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
|
|
3967
|
+
txtFieldOTPText5.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 4)])
|
|
3968
|
+
txtFieldOTPText6.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 5)])
|
|
3969
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
3973
|
+
// Handle card number input for both old and new card fields
|
|
3974
|
+
if textField == cardNumberTextField.textField || textField == txtFieldCardNumberNewCardView {
|
|
3975
|
+
if string.isEmpty {
|
|
3976
|
+
let modifiedText = NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)
|
|
3977
|
+
textField.text = formatCardNumber(modifiedText)
|
|
3978
|
+
return false
|
|
3979
|
+
}
|
|
3980
|
+
|
|
3981
|
+
let text = (textField.text ?? "") + string
|
|
3982
|
+
if text.filter({ $0.isNumber }).count > 16 {
|
|
3983
|
+
return false
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
textField.text = formatCardNumber(text)
|
|
3987
|
+
if let lastCharacter = text.last, lastCharacter == " " {
|
|
3988
|
+
textField.text = String(text.dropLast())
|
|
3989
|
+
}
|
|
3990
|
+
|
|
3991
|
+
return false
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3994
|
+
// Handle card CVV input for both old and new card fields
|
|
3995
|
+
else if textField == cardCvvTextField.textField || textField == txtFieldCVVNewCardView || textField == txtFieldCVVUpdateCardView {
|
|
3996
|
+
let maxLength = 3
|
|
3997
|
+
let currentString = (textField.text ?? "") as NSString
|
|
3998
|
+
let newString = currentString.replacingCharacters(in: range, with: string)
|
|
3999
|
+
return newString.count <= maxLength
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
// Handle card expiry date input for both old and new card fields
|
|
4003
|
+
else if textField == cardExpiryTextField.textField || textField == txtFieldExpiryDateNewCardView || textField == txtFieldExpireDateUpdateCardView {
|
|
4004
|
+
if range.length > 0 {
|
|
4005
|
+
return true
|
|
4006
|
+
}
|
|
4007
|
+
if string.isEmpty {
|
|
4008
|
+
return false
|
|
4009
|
+
}
|
|
4010
|
+
if range.location > 6 {
|
|
4011
|
+
return false
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
var originalText = textField.text ?? ""
|
|
4015
|
+
let replacementText = string.replacingOccurrences(of: " ", with: "")
|
|
4016
|
+
|
|
4017
|
+
// Ensure only digits are allowed
|
|
4018
|
+
if !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: replacementText)) {
|
|
4019
|
+
return false
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
// Insert "/" after MM
|
|
4023
|
+
if range.location == 2 {
|
|
4024
|
+
originalText.append("/")
|
|
4025
|
+
}
|
|
4026
|
+
|
|
4027
|
+
textField.text = originalText + replacementText
|
|
4028
|
+
return false
|
|
4029
|
+
}
|
|
4030
|
+
|
|
4031
|
+
// Handle OTP input fields
|
|
4032
|
+
else if [txtFieldOTPText1, txtFieldOTPText2, txtFieldOTPText3, txtFieldOTPText4, txtFieldOTPText5, txtFieldOTPText6].contains(textField) {
|
|
4033
|
+
if string.count == 1 {
|
|
4034
|
+
// Single character input
|
|
4035
|
+
textField.text = string
|
|
4036
|
+
switch textField {
|
|
4037
|
+
case txtFieldOTPText1:
|
|
4038
|
+
txtFieldOTPText2.becomeFirstResponder()
|
|
4039
|
+
case txtFieldOTPText2:
|
|
4040
|
+
txtFieldOTPText3.becomeFirstResponder()
|
|
4041
|
+
case txtFieldOTPText3:
|
|
4042
|
+
txtFieldOTPText4.becomeFirstResponder()
|
|
4043
|
+
case txtFieldOTPText4:
|
|
4044
|
+
txtFieldOTPText5.becomeFirstResponder()
|
|
4045
|
+
case txtFieldOTPText5:
|
|
4046
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
4047
|
+
case txtFieldOTPText6:
|
|
4048
|
+
txtFieldOTPText6.resignFirstResponder()
|
|
4049
|
+
// Call OTP verification API when the last field is filled
|
|
4050
|
+
if getCombinedOTP().count == 6 {
|
|
4051
|
+
otpVerificationApi()
|
|
4052
|
+
}
|
|
4053
|
+
default:
|
|
4054
|
+
break
|
|
4055
|
+
}
|
|
4056
|
+
updateViewColors()
|
|
4057
|
+
return false
|
|
4058
|
+
} else if string.isEmpty {
|
|
4059
|
+
// Handle backspace
|
|
4060
|
+
textField.text = ""
|
|
4061
|
+
switch textField {
|
|
4062
|
+
case txtFieldOTPText6:
|
|
4063
|
+
txtFieldOTPText5.becomeFirstResponder()
|
|
4064
|
+
case txtFieldOTPText5:
|
|
4065
|
+
txtFieldOTPText4.becomeFirstResponder()
|
|
4066
|
+
case txtFieldOTPText4:
|
|
4067
|
+
txtFieldOTPText3.becomeFirstResponder()
|
|
4068
|
+
case txtFieldOTPText3:
|
|
4069
|
+
txtFieldOTPText2.becomeFirstResponder()
|
|
4070
|
+
case txtFieldOTPText2:
|
|
4071
|
+
txtFieldOTPText1.becomeFirstResponder()
|
|
4072
|
+
default:
|
|
4073
|
+
break
|
|
4074
|
+
}
|
|
4075
|
+
updateViewColors()
|
|
4076
|
+
return false
|
|
4077
|
+
}
|
|
4078
|
+
return textField.text?.count == 0
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
return true
|
|
4082
|
+
}
|
|
4083
|
+
|
|
4084
|
+
// Helper method to format the card number with spaces
|
|
4085
|
+
func formatCardNumber(_ input: String) -> String {
|
|
4086
|
+
var formattedString = ""
|
|
4087
|
+
let trimmedString = input.replacingOccurrences(of: " ", with: "")
|
|
4088
|
+
for i in 0..<trimmedString.count {
|
|
4089
|
+
if i > 0 && i % 4 == 0 {
|
|
4090
|
+
formattedString += " "
|
|
4091
|
+
}
|
|
4092
|
+
let index = trimmedString.index(trimmedString.startIndex, offsetBy: i)
|
|
4093
|
+
formattedString.append(trimmedString[index])
|
|
4094
|
+
}
|
|
4095
|
+
return formattedString
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
// Update the view colors based on text presence in OTP fields
|
|
4099
|
+
private func updateViewColors() {
|
|
4100
|
+
viewTextOTP1.backgroundColor = txtFieldOTPText1.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4101
|
+
viewTextOTP2.backgroundColor = txtFieldOTPText2.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4102
|
+
viewTextOTP3.backgroundColor = txtFieldOTPText3.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4103
|
+
viewTextOTP4.backgroundColor = txtFieldOTPText4.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4104
|
+
viewTextOTP5.backgroundColor = txtFieldOTPText5.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4105
|
+
viewTextOTP6.backgroundColor = txtFieldOTPText6.text?.isEmpty == false ? .systemBlue : .systemGray
|
|
4106
|
+
}
|
|
4107
|
+
|
|
4108
|
+
@objc func textFieldDidChange(_ textField: UITextField) {
|
|
4109
|
+
guard let otpCode = textField.text, otpCode.count >= 6, textField.textContentType == .oneTimeCode else { return }
|
|
4110
|
+
// Split the OTP into each text field
|
|
4111
|
+
txtFieldOTPText1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
|
|
4112
|
+
txtFieldOTPText2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
|
|
4113
|
+
txtFieldOTPText3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
|
|
4114
|
+
txtFieldOTPText4.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
|
|
4115
|
+
txtFieldOTPText5.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 4)])
|
|
4116
|
+
txtFieldOTPText6.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 5)])
|
|
4117
|
+
// Automatically move to the last text field
|
|
4118
|
+
txtFieldOTPText6.becomeFirstResponder()
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
func getCombinedOTP() -> String {
|
|
4122
|
+
let otp1 = txtFieldOTPText1.text ?? ""
|
|
4123
|
+
let otp2 = txtFieldOTPText2.text ?? ""
|
|
4124
|
+
let otp3 = txtFieldOTPText3.text ?? ""
|
|
4125
|
+
let otp4 = txtFieldOTPText4.text ?? ""
|
|
4126
|
+
let otp5 = txtFieldOTPText5.text ?? ""
|
|
4127
|
+
let otp6 = txtFieldOTPText6.text ?? ""
|
|
4128
|
+
|
|
4129
|
+
return otp1 + otp2 + otp3 + otp4 + otp5 + otp6
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
// UITextFieldDelegate methods
|
|
4133
|
+
func textFieldDidBeginEditing(_ textField: UITextField) {
|
|
4134
|
+
if textField == cardNumberTextField.textField {
|
|
4135
|
+
viewTextFieldCardNumber.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4136
|
+
} else if textField == cardExpiryTextField.textField {
|
|
4137
|
+
viewTxtFieldExpiryDate.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4138
|
+
} else if textField == cardCvvTextField.textField {
|
|
4139
|
+
viewTxtFieldCVV.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4140
|
+
} else if textField == cardNameTextField.textField {
|
|
4141
|
+
viewTxtFieldNameOnCard.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4142
|
+
}
|
|
4143
|
+
else if textField == txtFieldEmail {
|
|
4144
|
+
viewTxtFieldEmail.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4145
|
+
}
|
|
4146
|
+
//Single Saved Card view
|
|
4147
|
+
else if textField == txtFieldCVVSingleSavedCard {
|
|
4148
|
+
viewTxtFieldCVVSingleSavedCard.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4149
|
+
}
|
|
4150
|
+
//Update Card View
|
|
4151
|
+
else if textField == txtFieldExpireDateUpdateCardView {
|
|
4152
|
+
viewTxtFieldExpireDateUpdateCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4153
|
+
}
|
|
4154
|
+
else if textField == txtFieldCVVUpdateCardView {
|
|
4155
|
+
viewtxtFieldCVVUpdateCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4156
|
+
}
|
|
4157
|
+
else if textField == txtFieldNameOnCardUpdateCardView {
|
|
4158
|
+
viewTxtFieldNameOnCardUpdateCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4159
|
+
}
|
|
4160
|
+
//NEW Card View
|
|
4161
|
+
else if textField == txtFieldCardNumberNewCardView {
|
|
4162
|
+
viewtxtFieldCardNumberNewCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4163
|
+
}
|
|
4164
|
+
else if textField == txtFieldExpiryDateNewCardView {
|
|
4165
|
+
viewtxtFieldExpiryDateNewCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4166
|
+
}
|
|
4167
|
+
else if textField == txtFieldCVVNewCardView {
|
|
4168
|
+
viewtxtFieldCVVNewCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4169
|
+
}
|
|
4170
|
+
else if textField == txtFieldNameOnCardNewCardView {
|
|
4171
|
+
viewtxtFieldNameOnCardNewCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4172
|
+
}
|
|
4173
|
+
//Bank View
|
|
4174
|
+
else if textField == txtFieldAccountName {
|
|
4175
|
+
viewtxtFieldAccountName.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4176
|
+
}
|
|
4177
|
+
else if textField == txtFieldRoutingNumber {
|
|
4178
|
+
viewtxtFieldRoutingNumber.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4179
|
+
}
|
|
4180
|
+
else if textField == txtFieldAccountType {
|
|
4181
|
+
viewtxtFieldAccountType.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4182
|
+
}
|
|
4183
|
+
else if textField == txtFieldAccountNumber {
|
|
4184
|
+
viewtxtFieldAccountNumber.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4185
|
+
}
|
|
4186
|
+
//New Bank Account View
|
|
4187
|
+
else if textField == txtFieldAccountNameNewAccountView {
|
|
4188
|
+
viewtxtFieldAccountNameNewAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4189
|
+
}
|
|
4190
|
+
else if textField == txtFieldRoutingNumberNewAccountView {
|
|
4191
|
+
viewtxtFieldRoutingNumberNewAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4192
|
+
}
|
|
4193
|
+
else if textField == txtFieldAccountTypeNewAccountView {
|
|
4194
|
+
viewtxtFieldAccountTypeNewAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4195
|
+
}
|
|
4196
|
+
else if textField == txtFieldAccountNumberNewAccountView {
|
|
4197
|
+
viewtxtFieldAccountNumberNewAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
|
|
4201
|
+
func textFieldDidEndEditing(_ textField: UITextField) {
|
|
4202
|
+
if textField == cardNumberTextField.textField {
|
|
4203
|
+
viewTextFieldCardNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
4204
|
+
} else if textField == cardExpiryTextField.textField {
|
|
4205
|
+
viewTxtFieldExpiryDate.layer.borderColor = UIColor.systemGray.cgColor
|
|
4206
|
+
} else if textField == cardCvvTextField.textField {
|
|
4207
|
+
viewTxtFieldCVV.layer.borderColor = UIColor.systemGray.cgColor
|
|
4208
|
+
} else if textField == cardNameTextField.textField {
|
|
4209
|
+
viewTxtFieldNameOnCard.layer.borderColor = UIColor.systemGray.cgColor
|
|
4210
|
+
}
|
|
4211
|
+
else if textField == txtFieldEmail {
|
|
4212
|
+
viewTxtFieldEmail.layer.borderColor = UIColor.systemGray.cgColor
|
|
4213
|
+
}
|
|
4214
|
+
else if textField == txtFieldCVVSingleSavedCard {
|
|
4215
|
+
viewTxtFieldCVVSingleSavedCard.layer.borderColor = UIColor.systemGray.cgColor
|
|
4216
|
+
}
|
|
4217
|
+
//Update Card View
|
|
4218
|
+
else if textField == txtFieldExpireDateUpdateCardView {
|
|
4219
|
+
viewTxtFieldExpireDateUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4220
|
+
}
|
|
4221
|
+
else if textField == txtFieldCVVUpdateCardView {
|
|
4222
|
+
viewtxtFieldCVVUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4223
|
+
}
|
|
4224
|
+
else if textField == txtFieldNameOnCardUpdateCardView {
|
|
4225
|
+
viewTxtFieldNameOnCardUpdateCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4226
|
+
}
|
|
4227
|
+
//NEW Card View
|
|
4228
|
+
else if textField == txtFieldCardNumberNewCardView {
|
|
4229
|
+
viewtxtFieldCardNumberNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4230
|
+
}
|
|
4231
|
+
else if textField == txtFieldExpiryDateNewCardView {
|
|
4232
|
+
viewtxtFieldExpiryDateNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4233
|
+
}
|
|
4234
|
+
else if textField == txtFieldCVVNewCardView {
|
|
4235
|
+
viewtxtFieldCVVNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4236
|
+
}
|
|
4237
|
+
else if textField == txtFieldNameOnCardNewCardView {
|
|
4238
|
+
viewtxtFieldNameOnCardNewCardView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4239
|
+
}
|
|
4240
|
+
//Bank View
|
|
4241
|
+
else if textField == txtFieldAccountName {
|
|
4242
|
+
viewtxtFieldAccountName.layer.borderColor = UIColor.systemGray.cgColor
|
|
4243
|
+
}
|
|
4244
|
+
else if textField == txtFieldRoutingNumber {
|
|
4245
|
+
viewtxtFieldRoutingNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
4246
|
+
}
|
|
4247
|
+
else if textField == txtFieldAccountType {
|
|
4248
|
+
viewtxtFieldAccountType.layer.borderColor = UIColor.systemGray.cgColor
|
|
4249
|
+
}
|
|
4250
|
+
else if textField == txtFieldAccountNumber {
|
|
4251
|
+
viewtxtFieldAccountNumber.layer.borderColor = UIColor.systemGray.cgColor
|
|
4252
|
+
}
|
|
4253
|
+
//New Bank Account View
|
|
4254
|
+
else if textField == txtFieldAccountNameNewAccountView {
|
|
4255
|
+
viewtxtFieldAccountNameNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4256
|
+
}
|
|
4257
|
+
else if textField == txtFieldRoutingNumberNewAccountView {
|
|
4258
|
+
viewtxtFieldRoutingNumberNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4259
|
+
}
|
|
4260
|
+
else if textField == txtFieldAccountTypeNewAccountView {
|
|
4261
|
+
viewtxtFieldAccountTypeNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4262
|
+
}
|
|
4263
|
+
else if textField == txtFieldAccountNumberNewAccountView {
|
|
4264
|
+
viewtxtFieldAccountNumberNewAccountView.layer.borderColor = UIColor.systemGray.cgColor
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4268
|
+
}
|
|
4269
|
+
|