@jimrising/easymerchantsdk-react-native 1.3.9 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.idea/caches/deviceStreaming.xml +77 -0
  2. package/README.md +140 -81
  3. package/android/.gradle/8.10/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.10/checksums/md5-checksums.bin +0 -0
  5. package/android/.gradle/8.10/checksums/sha1-checksums.bin +0 -0
  6. package/android/.gradle/8.10/fileHashes/fileHashes.lock +0 -0
  7. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  8. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  9. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  10. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  11. package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
  12. package/ios/Classes/EasyMerchantSdk.m +106 -55
  13. package/ios/Classes/EasyMerchantSdk.swift +199 -77
  14. package/ios/Classes/EasyPayViewController.swift +1 -1
  15. package/ios/CustomComponents/DatePickerHandler.swift +15 -4
  16. package/ios/EnvironmentConfig.swift +32 -30
  17. package/ios/Models/Request.swift +176 -14
  18. package/ios/Models/Result.swift +12 -5
  19. package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +845 -358
  20. package/ios/Pods/ViewControllers/BaseVC.swift +39 -35
  21. package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +1975 -170
  22. package/ios/Pods/ViewControllers/CountryListVC.swift +0 -1
  23. package/ios/Pods/ViewControllers/EmailVerificationVC.swift +74 -5
  24. package/ios/Pods/ViewControllers/GrailPayVC.swift +131 -107
  25. package/ios/Pods/ViewControllers/OTPVerificationVC.swift +296 -106
  26. package/ios/Pods/ViewControllers/PaymentDoneVC.swift +21 -12
  27. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +1273 -513
  28. package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +104 -12
  29. package/ios/easymerchantsdk.podspec +1 -1
  30. package/ios/easymerchantsdk.storyboard +467 -412
  31. package/package.json +1 -1
@@ -76,6 +76,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
76
76
  @IBOutlet weak var viewTxtFieldStartDateCard: UIView!
77
77
  @IBOutlet weak var imgViewChosePlanCardDropIcon: UIImageView!
78
78
  @IBOutlet weak var imgViewCalenderIconCard: UIImageView!
79
+ @IBOutlet weak var txtFieldEmailCardView: TextFieldStackView!
80
+ @IBOutlet weak var viewTxtFieldEmailCardView: UIView!
79
81
 
80
82
  @IBOutlet weak var btnScanCard: UIButton!
81
83
 
@@ -176,7 +178,10 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
176
178
  @IBOutlet weak var viewTextFieldConfirmAccount: UIView!
177
179
  @IBOutlet weak var txtFieldSelectPlanViewBankFields: TextFieldStackView!
178
180
  @IBOutlet weak var txtFieldSelectDateViewBankFields: TextFieldStackView!
181
+ @IBOutlet weak var txtFieldEmailAccountView: TextFieldStackView!
182
+ @IBOutlet weak var viewTxtFieldEmailAccountView: UIView!
179
183
 
184
+ @IBOutlet weak var viewSaveCardForFutureCardView: UIStackView!
180
185
  @IBOutlet weak var heightViewBankFields: NSLayoutConstraint!
181
186
 
182
187
  //GrailPay
@@ -199,6 +204,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
199
204
  @IBOutlet weak var txtFieldChosePlanGrailPayBankView: TextFieldStackView!
200
205
  @IBOutlet weak var txtFieldSelectDateGrailPayBankView: TextFieldStackView!
201
206
  @IBOutlet weak var bankIconGrailPayBankView: UIImageView!
207
+ @IBOutlet weak var viewSaveAccountForFutureGrailPayView: UIStackView!
202
208
 
203
209
  //New GrailPay Account
204
210
  @IBOutlet weak var viewAddNewGrailPayAccount: UIView!
@@ -223,6 +229,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
223
229
  @IBOutlet weak var txtFieldChosePlanNewGrailPayBankView: TextFieldStackView!
224
230
  @IBOutlet weak var txtFieldSelectDateNewGrailPayBankView: TextFieldStackView!
225
231
  @IBOutlet weak var imgViewBankIconGrailPayNewBank: UIImageView!
232
+ @IBOutlet weak var viewSaveAccountForFututeNewGrailPayAccountView: UIStackView!
226
233
 
227
234
  //SavedBank
228
235
  @IBOutlet weak var viewSingleSavedAccount: UIView!
@@ -265,6 +272,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
265
272
 
266
273
  @IBOutlet weak var heightViewNewAccountFields: NSLayoutConstraint!
267
274
  @IBOutlet weak var heightSubViewNewAccountFields: NSLayoutConstraint!
275
+ @IBOutlet weak var viewSaveAccountForFutureNewAccountView: UIStackView!
276
+
268
277
 
269
278
  //Crypto
270
279
  @IBOutlet weak var viewCrypto: UIView!
@@ -339,7 +348,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
339
348
  var selectedBank: BankAccountModel?
340
349
  var isSelectForPayBank: Bool = false
341
350
  var selectedBankIndex: Int? = nil
342
- var arrAccountType = ["Saving", "Checking"]
351
+ var arrAccountType = ["saving", "checking", "ledger"]
343
352
 
344
353
  var agreeTermsAndCondtition: Bool = false
345
354
 
@@ -353,7 +362,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
353
362
  var isFrom = String()
354
363
 
355
364
  //Blink Card
356
- // var blinkCardRecognizer: MBCBlinkCardRecognizer!
365
+ // var blinkCardRecognizer: MBCBlinkCardRecognizer!
357
366
 
358
367
  // Variables for Card Scanning Data Back
359
368
  var cardNumber: String?
@@ -388,6 +397,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
388
397
 
389
398
  var startDatePickerHandler: DatePickerHandler?
390
399
 
400
+ var isSavedNewCard: Bool = false
401
+
391
402
  //MARK: - View Did Load
392
403
  override func viewDidLoad() {
393
404
  super.viewDidLoad()
@@ -412,10 +423,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
412
423
 
413
424
  //// Check if billingInfoData is available
414
425
  if let billingInfoData = request.billingInfoData,
415
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
416
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
417
- // If `submitButtonText` is not empty, use it; otherwise, default to "Next (Billing Info)"
418
- let buttonText = (request?.submitButtonText?.isEmpty == false ? request!.submitButtonText! + " (Billing Info)" : "Next (Billing Info)")
426
+ let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
427
+
428
+ let billingVisible = fieldSection.visibility.billing
429
+ let suffix = billingVisible ? " (Billing Info)" : " (Additional Info)"
430
+ let buttonText = (request?.submitButtonText?.isEmpty == false
431
+ ? request!.submitButtonText! + suffix
432
+ : "Next" + suffix)
419
433
 
420
434
  btnNext.setTitle(buttonText, for: .normal)
421
435
  btnPayNowNewCardView.setTitle(buttonText, for: .normal)
@@ -541,10 +555,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
541
555
  self.txtFieldSelectDateGrailPayBankView.isHidden = false
542
556
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = false
543
557
 
544
- self.heightViewBankFields.constant = 710
558
+ if request.saveAccount == false {
559
+ self.heightViewBankFields.constant = 790
560
+ self.heightViewNewAccountFields.constant = 788
561
+ } else {
562
+ self.heightViewBankFields.constant = 836
563
+ self.heightViewNewAccountFields.constant = 844
564
+ }
565
+
566
+ if request.saveCard == false {
567
+ self.heightViewNewCardFields.constant = 595
568
+ } else {
569
+ self.heightViewNewCardFields.constant = 648
570
+ }
545
571
 
546
- self.heightViewNewCardFields.constant = 624
547
- self.heightViewNewAccountFields.constant = 808
548
572
  self.heightSubViewNewAccountFields.constant = 738
549
573
  } else {
550
574
  self.txtFieldStartDateCard.isHidden = true
@@ -556,9 +580,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
556
580
  self.txtFieldSelectDateGrailPayBankView.isHidden = true
557
581
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = true
558
582
 
559
- self.heightViewBankFields.constant = 600
560
- self.heightViewNewCardFields.constant = 529
561
- self.heightViewNewAccountFields.constant = 713
583
+ if request.saveAccount == false {
584
+ self.heightViewBankFields.constant = 700
585
+ self.heightViewNewAccountFields.constant = 690
586
+ } else {
587
+ self.heightViewBankFields.constant = 740
588
+ self.heightViewNewAccountFields.constant = 738
589
+ }
590
+
591
+ if request.saveCard == false {
592
+ self.heightViewNewCardFields.constant = 500
593
+ } else {
594
+ self.heightViewNewCardFields.constant = 553
595
+ }
596
+
562
597
  self.heightSubViewNewAccountFields.constant = 643
563
598
  }
564
599
 
@@ -588,9 +623,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
588
623
  self.txtFieldSelectDateGrailPayBankView.isHidden = true
589
624
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = true
590
625
 
591
- self.heightViewBankFields.constant = 506
592
- self.heightViewNewCardFields.constant = 434
593
- self.heightViewNewAccountFields.constant = 628
626
+ if request.saveAccount == false {
627
+ self.heightViewBankFields.constant = 604
628
+ self.heightViewNewAccountFields.constant = 600
629
+ } else {
630
+ self.heightViewBankFields.constant = 644
631
+ self.heightViewNewAccountFields.constant = 660
632
+ }
633
+
634
+ if request.saveCard == false {
635
+ self.heightViewNewCardFields.constant = 404
636
+ } else {
637
+ self.heightViewNewCardFields.constant = 458
638
+ }
639
+
594
640
  self.heightSubViewNewAccountFields.constant = 558
595
641
  }
596
642
 
@@ -667,10 +713,24 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
667
713
  else {
668
714
  self.viewSingleSavedAccount.isHidden = true
669
715
  self.viewBankFields.isHidden = true
670
- self.viewBtnShowSavedCards.isHidden = false
671
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
672
- self.viewBtnShowSavedCardHeight.constant = 50
673
- self.viewBtnShowSavedCardTopCon.constant = 20
716
+
717
+ // self.viewBtnShowSavedCards.isHidden = false
718
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
719
+ // self.viewBtnShowSavedCardHeight.constant = 50
720
+ // self.viewBtnShowSavedCardTopCon.constant = 20
721
+
722
+ if request.saveCard == false {
723
+ self.viewBtnShowSavedCards.isHidden = true
724
+ self.viewBtnShowSavedCardHeight.constant = 0
725
+ self.viewBtnShowSavedCardTopCon.constant = 0
726
+ }
727
+ else {
728
+ self.viewBtnShowSavedCards.isHidden = false
729
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
730
+ self.viewBtnShowSavedCardHeight.constant = 50
731
+ self.viewBtnShowSavedCardTopCon.constant = 20
732
+ }
733
+
674
734
  self.OTPView.isHidden = true
675
735
  self.emailView.isHidden = true
676
736
  self.viewCardFields.isHidden = false
@@ -779,10 +839,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
779
839
  }
780
840
  else {
781
841
  // self.viewBankFields.isHidden = false
782
- self.viewBtnShowSavedCards.isHidden = false
783
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
784
- self.viewBtnShowSavedCardHeight.constant = 50
785
- self.viewBtnShowSavedCardTopCon.constant = 20
842
+ // self.viewBtnShowSavedCards.isHidden = false
843
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
844
+ // self.viewBtnShowSavedCardHeight.constant = 50
845
+ // self.viewBtnShowSavedCardTopCon.constant = 20
846
+
847
+ if request.saveAccount == false {
848
+ self.viewBtnShowSavedCards.isHidden = true
849
+ self.viewBtnShowSavedCardHeight.constant = 0
850
+ self.viewBtnShowSavedCardTopCon.constant = 0
851
+ }
852
+ else {
853
+ self.viewBtnShowSavedCards.isHidden = false
854
+ self.lblBtnShowSaveCard.text = "Show Saved Accounts"
855
+ self.viewBtnShowSavedCardHeight.constant = 50
856
+ self.viewBtnShowSavedCardTopCon.constant = 20
857
+ }
858
+
786
859
  self.OTPView.isHidden = true
787
860
  self.emailView.isHidden = true
788
861
  self.viewCardFields.isHidden = true
@@ -1162,6 +1235,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1162
1235
  cardExpiryTextField.textField.delegate = self
1163
1236
  cardCvvTextField.textField.delegate = self
1164
1237
  cardNameTextField.textField.delegate = self
1238
+ txtFieldEmailCardView.textField.delegate = self
1165
1239
 
1166
1240
  txtFieldEmail.delegate = self
1167
1241
 
@@ -1185,20 +1259,42 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1185
1259
  txtFieldAccountTypeNewAccountView.delegate = self
1186
1260
  txtFieldAccountNumber.delegate = self
1187
1261
  txtFieldConfirmBankAccount.delegate = self
1262
+ txtFieldEmailAccountView.textField.delegate = self
1188
1263
  }
1189
1264
 
1190
1265
  private func updateSaveButtons() {
1191
1266
  let isSavedCard = request?.saveCard ?? false
1192
1267
  let isSavedAccount = request?.saveAccount ?? false
1193
1268
 
1194
- let cardImageName = isSavedCard ? "checkmark.square.fill" : "square"
1195
- let accountImageName = isSavedAccount ? "checkmark.square.fill" : "square"
1269
+ let defaultImageName = "square" // always show unselected initially
1270
+
1271
+ // Card Buttons: Show/hide based on saveCard
1272
+ btnCheckBoxSavedCard.isHidden = !isSavedCard
1273
+ btnSavedCardForFutureNewCardView.isHidden = !isSavedCard
1196
1274
 
1197
- btnCheckBoxSavedCard.setImage(UIImage(systemName: cardImageName), for: .normal)
1198
- btnSavedCardForFutureNewCardView.setImage(UIImage(systemName: cardImageName), for: .normal)
1275
+ if isSavedCard {
1276
+ btnCheckBoxSavedCard.setImage(UIImage(systemName: defaultImageName), for: .normal)
1277
+ btnSavedCardForFutureNewCardView.setImage(UIImage(systemName: defaultImageName), for: .normal)
1278
+ }
1199
1279
 
1200
- btnCheckSavedAccountForFuture.setImage(UIImage(systemName: accountImageName), for: .normal)
1201
- btnSavedNewAccountForFuture.setImage(UIImage(systemName: accountImageName), for: .normal)
1280
+ // Account Buttons: Show/hide based on saveAccount
1281
+ let accountButtons: [UIButton] = [
1282
+ btnCheckBoxGrailPaySaveAccount,
1283
+ btnCheckBoxGrailPayNewAccountSaveAccount
1284
+ ]
1285
+
1286
+ for button in accountButtons {
1287
+ button.isHidden = !isSavedAccount
1288
+ if isSavedAccount {
1289
+ button.setImage(UIImage(systemName: defaultImageName), for: .normal)
1290
+ }
1291
+ }
1292
+
1293
+ // Other related UI changes for account
1294
+ viewSaveCardForFutureCardView?.isHidden = !isSavedAccount
1295
+ viewSaveAccountForFutureNewAccountView?.isHidden = !isSavedAccount
1296
+ viewSaveAccountForFutureGrailPayView?.isHidden = !isSavedAccount
1297
+ viewSaveAccountForFututeNewGrailPayAccountView?.isHidden = !isSavedAccount
1202
1298
  }
1203
1299
 
1204
1300
  //MARK: - Term & Conditions setup for normal bank fields view
@@ -1760,53 +1856,88 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1760
1856
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
1761
1857
  print("Billing Info Data: \(jsonDict)")
1762
1858
 
1763
- let cvvText = txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1764
-
1765
- if cvvText.isEmpty {
1766
- self.showAlert(title: "Missing CVV", message: "Please enter the CVV to proceed.")
1767
- return
1768
- } else if cvvText.count < 3 {
1769
- self.showAlert(title: "Invalid CVV", message: "CVV must be at least 3 digits.")
1770
- return
1771
- }
1772
-
1773
- // Recurring Plan + Date Validation (only if is_recurring is true)
1774
- if let req = self.request, req.is_recurring == true {
1775
- if txtFieldSelectPlanSingleSavedCard.text.isEmpty {
1776
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1777
- return
1778
- }
1859
+ do {
1860
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
1779
1861
 
1780
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
1781
- if txtFieldSelectDateSingleSavedCard.text.isEmpty {
1782
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
1862
+ DispatchQueue.main.async {
1863
+ let cvvText = self.txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1864
+
1865
+ if cvvText.isEmpty {
1866
+ self.showAlert(title: "Missing CVV", message: "Please enter the CVV to proceed.")
1783
1867
  return
1868
+ } else if cvvText.count < 3 {
1869
+ self.showAlert(title: "Invalid CVV", message: "CVV must be at least 3 digits.")
1870
+ return
1871
+ }
1872
+
1873
+ // Recurring Plan + Date Validation (only if is_recurring is true)
1874
+ if let req = self.request, req.is_recurring == true {
1875
+ if self.txtFieldSelectPlanSingleSavedCard.text.isEmpty {
1876
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1877
+ return
1878
+ }
1879
+
1880
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
1881
+ if self.txtFieldSelectDateSingleSavedCard.text.isEmpty {
1882
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
1883
+ return
1884
+ }
1885
+ }
1886
+ }
1887
+
1888
+ // Redirect based on billing visibility
1889
+ if fieldSection.visibility.billing {
1890
+ // Instantiate BillingInfoVC and pass the selected card data and CVV text
1891
+ let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1892
+
1893
+ billingInfoVC.isFrom = "SavedCards"
1894
+ billingInfoVC.selectedCard = self.selectedCard // Passing the selected card data
1895
+ billingInfoVC.cvvText = cvvText // Passing the CVV text
1896
+ billingInfoVC.amount = Int(self.request.amount ?? 0)
1897
+ billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
1898
+
1899
+ if let billingInfoData = self.request.billingInfoData {
1900
+ billingInfoVC.billingInfoData = billingInfoData
1901
+ }
1902
+
1903
+ billingInfoVC.request = self.request
1904
+ billingInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
1905
+ billingInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
1906
+
1907
+ billingInfoVC.billingInfo = fieldSection.billing
1908
+ billingInfoVC.additionalInfo = fieldSection.additional
1909
+ billingInfoVC.visibility = fieldSection.visibility
1910
+
1911
+ // Navigate to BillingInfoVC
1912
+ self.navigationController?.pushViewController(billingInfoVC, animated: true)
1913
+ }
1914
+ else {
1915
+ let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
1916
+ additionalInfoVC.isFrom = "SavedCards"
1917
+ additionalInfoVC.selectedCard = self.selectedCard // Passing the selected card data
1918
+ additionalInfoVC.cvvText = cvvText // Passing the CVV text
1919
+ additionalInfoVC.amount = Int(self.request.amount ?? 0)
1920
+ additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
1921
+
1922
+ if let billingInfoData = self.request.billingInfoData {
1923
+ additionalInfoVC.billingInfoData = billingInfoData
1924
+ }
1925
+
1926
+ additionalInfoVC.request = self.request
1927
+ additionalInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
1928
+ additionalInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
1929
+
1930
+ additionalInfoVC.billingInfo = fieldSection.billing
1931
+ additionalInfoVC.additionalInfo = fieldSection.additional
1932
+ additionalInfoVC.visibility = fieldSection.visibility
1933
+
1934
+ self.navigationController?.pushViewController(additionalInfoVC, animated: true)
1784
1935
  }
1785
1936
  }
1786
1937
  }
1787
-
1788
- // Instantiate BillingInfoVC and pass the selected card data and CVV text
1789
- let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1790
-
1791
- billingInfoVC.isFrom = "SavedCards"
1792
- billingInfoVC.selectedCard = selectedCard // Passing the selected card data
1793
- billingInfoVC.cvvText = cvvText // Passing the CVV text
1794
- billingInfoVC.amount = Int(request.amount)
1795
- billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
1796
-
1797
- // Pass the billing info data and auth token
1798
- if let billingInfoData = request.billingInfoData,
1799
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
1800
- let jsonDict = json as? [String: Any] {
1801
- billingInfoVC.billingInfoData = jsonDict
1938
+ catch {
1939
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
1802
1940
  }
1803
-
1804
- billingInfoVC.request = self.request
1805
- billingInfoVC.chosenPlan = txtFieldSelectPlanSingleSavedCard.text
1806
- billingInfoVC.startDate = txtFieldSelectDateSingleSavedCard.text
1807
-
1808
- // Navigate to BillingInfoVC
1809
- self.navigationController?.pushViewController(billingInfoVC, animated: true)
1810
1941
  }
1811
1942
  else {
1812
1943
  // If billingInfoData is nil or empty, set the button title to "Pay Now"
@@ -1887,99 +2018,140 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1887
2018
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
1888
2019
  print("Billing Info Data: \(jsonDict)")
1889
2020
 
1890
- // Retrieve and trim text field values (removing leading and trailing whitespace)
1891
- let cardNumber = txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1892
- let expiryDate = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1893
- let cvv = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1894
- let nameOnCard = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1895
-
1896
- // Check if any field is empty
1897
- if cardNumber.isEmpty || expiryDate.isEmpty || cvv.isEmpty || nameOnCard.isEmpty {
1898
- let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
1899
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1900
- self.present(alert, animated: true, completion: nil)
1901
- return
1902
- }
1903
-
1904
- // Validate expiry date format
1905
- let expiryDateFormat = "MM/yyyy"
1906
- let dateFormatter = DateFormatter()
1907
- dateFormatter.dateFormat = expiryDateFormat
1908
- dateFormatter.locale = Locale(identifier: "en_US_POSIX")
1909
-
1910
- // Split the expiry date and validate its format
1911
- let exp = expiryDate.split(separator: "/")
1912
- if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
1913
- let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
1914
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1915
- self.present(alert, animated: true, completion: nil)
1916
- return
1917
- }
1918
-
1919
- // Check if the expiry date is valid
1920
- if let expiryDateObj = dateFormatter.date(from: expiryDate) {
1921
- // Check if the expiry date is in the past
1922
- let currentDate = Date()
1923
- let calendar = Calendar.current
1924
- let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
1925
- if expiryDateObj < currentMonthYear! {
1926
- let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
1927
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1928
- self.present(alert, animated: true, completion: nil)
1929
- return
1930
- }
1931
- } else {
1932
- let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
1933
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1934
- self.present(alert, animated: true, completion: nil)
1935
- return
1936
- }
1937
-
1938
- // Recurring Plan + Date Validation (only if is_recurring is true)
1939
- if let req = self.request, req.is_recurring == true {
1940
- if txtFieldSelectPlanNewCardView.text.isEmpty {
1941
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1942
- return
1943
- }
2021
+ do {
2022
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
1944
2023
 
1945
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
1946
- if txtFieldSelectDateNewCardView.text.isEmpty {
1947
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
2024
+ DispatchQueue.main.async {
2025
+ // Retrieve and trim text field values (removing leading and trailing whitespace)
2026
+ let cardNumber = self.txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2027
+ let expiryDate = self.txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2028
+ let cvv = self.txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2029
+ let nameOnCard = self.txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2030
+
2031
+ // Check if any field is empty
2032
+ if cardNumber.isEmpty || expiryDate.isEmpty || cvv.isEmpty || nameOnCard.isEmpty {
2033
+ let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
2034
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2035
+ self.present(alert, animated: true, completion: nil)
2036
+ return
2037
+ }
2038
+
2039
+ // Validate expiry date format
2040
+ let expiryDateFormat = "MM/yyyy"
2041
+ let dateFormatter = DateFormatter()
2042
+ dateFormatter.dateFormat = expiryDateFormat
2043
+ dateFormatter.locale = Locale(identifier: "en_US_POSIX")
2044
+
2045
+ // Split the expiry date and validate its format
2046
+ let exp = expiryDate.split(separator: "/")
2047
+ if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
2048
+ let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
2049
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2050
+ self.present(alert, animated: true, completion: nil)
2051
+ return
2052
+ }
2053
+
2054
+ // Check if the expiry date is valid
2055
+ if let expiryDateObj = dateFormatter.date(from: expiryDate) {
2056
+ // Check if the expiry date is in the past
2057
+ let currentDate = Date()
2058
+ let calendar = Calendar.current
2059
+ let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
2060
+ if expiryDateObj < currentMonthYear! {
2061
+ let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
2062
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2063
+ self.present(alert, animated: true, completion: nil)
2064
+ return
2065
+ }
2066
+ } else {
2067
+ let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
2068
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2069
+ self.present(alert, animated: true, completion: nil)
1948
2070
  return
1949
2071
  }
2072
+
2073
+ // Recurring Plan + Date Validation (only if is_recurring is true)
2074
+ if let req = self.request, req.is_recurring == true {
2075
+ if self.txtFieldSelectPlanNewCardView.text.isEmpty {
2076
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
2077
+ return
2078
+ }
2079
+
2080
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
2081
+ if self.txtFieldSelectDateNewCardView.text.isEmpty {
2082
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
2083
+ return
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ // Redirect based on billing visibility
2089
+ if fieldSection.visibility.billing {
2090
+ // Instantiate BillingInfoVC and pass the card details
2091
+ let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2092
+
2093
+ // Pass the card details
2094
+ billingInfoVC.cardNumber = cardNumber
2095
+ billingInfoVC.expiryDate = expiryDate
2096
+ billingInfoVC.cvv = cvv
2097
+ billingInfoVC.nameOnCard = nameOnCard
2098
+ billingInfoVC.isSavedNewCard = self.isSavedNewCardForFuture
2099
+
2100
+ billingInfoVC.isFrom = "AddNewCard"
2101
+ billingInfoVC.amount = Int(self.request.amount ?? 0)
2102
+ billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2103
+
2104
+ if let billingInfoData = self.request.billingInfoData {
2105
+ billingInfoVC.billingInfoData = billingInfoData
2106
+ }
2107
+
2108
+ billingInfoVC.request = self.request
2109
+ billingInfoVC.chosenPlan = self.txtFieldSelectPlanNewCardView.text
2110
+ billingInfoVC.startDate = self.txtFieldSelectDateNewCardView.text
2111
+
2112
+ billingInfoVC.billingInfo = fieldSection.billing
2113
+ billingInfoVC.additionalInfo = fieldSection.additional
2114
+ billingInfoVC.visibility = fieldSection.visibility
2115
+
2116
+ // Navigate to BillingInfoVC
2117
+ self.navigationController?.pushViewController(billingInfoVC, animated: true)
2118
+ }
2119
+ else {
2120
+ let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2121
+
2122
+ // Pass the card details
2123
+ additionalInfoVC.cardNumber = cardNumber
2124
+ additionalInfoVC.expiryDate = expiryDate
2125
+ additionalInfoVC.cvv = cvv
2126
+ additionalInfoVC.nameOnCard = nameOnCard
2127
+ additionalInfoVC.isSavedNewCard = self.isSavedNewCardForFuture
2128
+
2129
+ additionalInfoVC.isFrom = "AddNewCard"
2130
+ additionalInfoVC.amount = Int(self.request.amount ?? 0)
2131
+ additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2132
+
2133
+ if let billingInfoData = self.request.billingInfoData {
2134
+ additionalInfoVC.billingInfoData = billingInfoData
2135
+ }
2136
+
2137
+ additionalInfoVC.request = self.request
2138
+ additionalInfoVC.chosenPlan = self.txtFieldSelectPlanNewCardView.text
2139
+ additionalInfoVC.startDate = self.txtFieldSelectDateNewCardView.text
2140
+
2141
+ additionalInfoVC.billingInfo = fieldSection.billing
2142
+ additionalInfoVC.additionalInfo = fieldSection.additional
2143
+ additionalInfoVC.visibility = fieldSection.visibility
2144
+
2145
+ self.navigationController?.pushViewController(additionalInfoVC, animated: true)
2146
+ }
1950
2147
  }
1951
2148
  }
1952
-
1953
- // Instantiate BillingInfoVC and pass the card details
1954
- let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1955
-
1956
- // Pass the card details
1957
- billingInfoVC.cardNumber = cardNumber
1958
- billingInfoVC.expiryDate = expiryDate
1959
- billingInfoVC.cvv = cvv
1960
- billingInfoVC.nameOnCard = nameOnCard
1961
- billingInfoVC.isSavedNewCard = isSavedNewCardForFuture
1962
-
1963
- billingInfoVC.isFrom = "AddNewCard"
1964
- billingInfoVC.amount = Int(request.amount)
1965
- billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
1966
-
1967
- // Pass the billing info data and auth token
1968
- if let billingInfoData = request.billingInfoData,
1969
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
1970
- let jsonDict = json as? [String: Any] {
1971
- billingInfoVC.billingInfoData = jsonDict
2149
+ catch {
2150
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
1972
2151
  }
1973
-
1974
- billingInfoVC.request = self.request
1975
- billingInfoVC.chosenPlan = txtFieldSelectPlanNewCardView.text
1976
- billingInfoVC.startDate = txtFieldSelectDateNewCardView.text
1977
-
1978
- // Navigate to BillingInfoVC
1979
- self.navigationController?.pushViewController(billingInfoVC, animated: true)
1980
2152
  }
1981
2153
  else {
1982
- if request.enable3DS == true {
2154
+ if request.secureAuthentication == true {
1983
2155
  threeDSecurePaymentNewCardApi(customerId: UserStoreSingleton.shared.customerId ?? "")
1984
2156
  }
1985
2157
  else {
@@ -2398,24 +2570,146 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2398
2570
  }
2399
2571
 
2400
2572
  guard agreeTermsAndCondtition else {
2401
- self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
2573
+ self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions.")
2402
2574
  return
2403
2575
  }
2404
2576
 
2405
2577
  if isSavedForFuture {
2406
- // Navigate to next screen without calling the API
2407
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2408
- vc.selectedPaymentMethod = "GrailPay"
2409
- vc.easyPayDelegate = self.easyPayDelegate
2410
- vc.grailPayAccountID = self.grailPayAccountID
2411
- vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2412
- vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2413
- self.navigationController?.pushViewController(vc, animated: true)
2578
+ //If billing info is available
2579
+ if let billingInfoData = request.billingInfoData {
2580
+ do {
2581
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2582
+
2583
+ DispatchQueue.main.async {
2584
+
2585
+ if let billingInfoData = self.request.billingInfoData,
2586
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2587
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2588
+ print("Billing Info Data: \(jsonDict)")
2589
+
2590
+ // Redirect based on billing visibility
2591
+ if fieldSection.visibility.billing {
2592
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2593
+ vc.billingInfoData = billingInfoData
2594
+ vc.request = self.request
2595
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2596
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2597
+ vc.selectedPaymentMethod = "GrailPay"
2598
+ vc.isSavedForFuture = self.isSavedForFuture
2599
+ vc.grailPayAccountID = self.grailPayAccountID
2600
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2601
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2602
+ vc.amount = self.amount
2603
+ vc.billingInfo = fieldSection.billing
2604
+ vc.additionalInfo = fieldSection.additional
2605
+ vc.visibility = fieldSection.visibility
2606
+ vc.easyPayDelegate = self.easyPayDelegate
2607
+ self.navigationController?.pushViewController(vc, animated: true)
2608
+ }
2609
+ else {
2610
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2611
+ vc.billingInfoData = billingInfoData
2612
+ vc.request = self.request
2613
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2614
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2615
+ vc.selectedPaymentMethod = "GrailPay"
2616
+ vc.isSavedForFuture = self.isSavedForFuture
2617
+ vc.grailPayAccountID = self.grailPayAccountID
2618
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2619
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2620
+ vc.amount = self.amount
2621
+ vc.billingInfo = fieldSection.billing
2622
+ vc.additionalInfo = fieldSection.additional
2623
+ vc.visibility = fieldSection.visibility
2624
+ vc.easyPayDelegate = self.easyPayDelegate
2625
+ self.navigationController?.pushViewController(vc, animated: true)
2626
+ }
2627
+ }
2628
+ }
2629
+ }
2630
+ catch {
2631
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2632
+ }
2633
+ }
2634
+ else {
2635
+ //If billing info is nil
2636
+ // Navigate to EmailVerificationVC directly
2637
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2638
+ vc.easyPayDelegate = self.easyPayDelegate
2639
+ vc.grailPayAccountID = self.grailPayAccountID
2640
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2641
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2642
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2643
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2644
+ vc.request = self.request
2645
+ vc.isSavedForFuture = self.isSavedForFuture
2646
+ vc.selectedPaymentMethod = "GrailPay"
2647
+ self.navigationController?.pushViewController(vc, animated: true)
2648
+ }
2414
2649
  } else {
2415
- // Proceed to call API if not saving for future
2416
- grailPayAccountChargeApi()
2650
+ // Check if billing info data exists and is valid JSON without save
2651
+ if let billingInfoData = request.billingInfoData {
2652
+ do {
2653
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2654
+
2655
+ DispatchQueue.main.async {
2656
+
2657
+ if let billingInfoData = self.request.billingInfoData,
2658
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2659
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2660
+ print("Billing Info Data: \(jsonDict)")
2661
+
2662
+ // Redirect based on billing visibility
2663
+ if fieldSection.visibility.billing {
2664
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2665
+ vc.billingInfoData = billingInfoData
2666
+ vc.request = self.request
2667
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2668
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2669
+ vc.selectedPaymentMethod = "GrailPay"
2670
+ vc.isSavedForFuture = self.isSavedForFuture
2671
+ vc.grailPayAccountID = self.grailPayAccountID
2672
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2673
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2674
+ vc.amount = self.amount
2675
+ vc.billingInfo = fieldSection.billing
2676
+ vc.additionalInfo = fieldSection.additional
2677
+ vc.visibility = fieldSection.visibility
2678
+ vc.easyPayDelegate = self.easyPayDelegate
2679
+ self.navigationController?.pushViewController(vc, animated: true)
2680
+ }
2681
+ else {
2682
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2683
+ vc.billingInfoData = billingInfoData
2684
+ vc.request = self.request
2685
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2686
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2687
+ vc.selectedPaymentMethod = "GrailPay"
2688
+ vc.isSavedForFuture = self.isSavedForFuture
2689
+ vc.grailPayAccountID = self.grailPayAccountID
2690
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2691
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2692
+ vc.amount = self.amount
2693
+ vc.billingInfo = fieldSection.billing
2694
+ vc.additionalInfo = fieldSection.additional
2695
+ vc.visibility = fieldSection.visibility
2696
+ vc.easyPayDelegate = self.easyPayDelegate
2697
+ self.navigationController?.pushViewController(vc, animated: true)
2698
+ }
2699
+ }
2700
+ }
2701
+ }
2702
+ catch {
2703
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2704
+ }
2705
+ }
2706
+ else {
2707
+ // Proceed to call API if billing info not available
2708
+ grailPayAccountChargeApi()
2709
+ }
2417
2710
  }
2418
2711
  } else {
2712
+ // Launch GrailPay account linking
2419
2713
  grailPaySource = .existingAccount
2420
2714
  launchGrailPay()
2421
2715
  }
@@ -2444,10 +2738,124 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2444
2738
  }
2445
2739
 
2446
2740
  if isSavedForFuture {
2447
- grailPayNewAccountSavingChargeApi()
2741
+ //If billing info is available
2742
+ if let billingInfoData = request.billingInfoData {
2743
+ do {
2744
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2745
+
2746
+ DispatchQueue.main.async {
2747
+
2748
+ if let billingInfoData = self.request.billingInfoData,
2749
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2750
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2751
+ print("Billing Info Data: \(jsonDict)")
2752
+
2753
+ // Redirect based on billing visibility
2754
+ if fieldSection.visibility.billing {
2755
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2756
+ vc.billingInfoData = billingInfoData
2757
+ vc.request = self.request
2758
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2759
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2760
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2761
+ vc.isSavedForFuture = self.isSavedForFuture
2762
+ vc.grailPayAccountID = self.newGrailPayAccountID
2763
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2764
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2765
+ vc.amount = self.amount
2766
+ vc.billingInfo = fieldSection.billing
2767
+ vc.additionalInfo = fieldSection.additional
2768
+ vc.visibility = fieldSection.visibility
2769
+ vc.easyPayDelegate = self.easyPayDelegate
2770
+ self.navigationController?.pushViewController(vc, animated: true)
2771
+ }
2772
+ else {
2773
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2774
+ vc.billingInfoData = billingInfoData
2775
+ vc.request = self.request
2776
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2777
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2778
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2779
+ vc.isSavedForFuture = self.isSavedForFuture
2780
+ vc.grailPayAccountID = self.newGrailPayAccountID
2781
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2782
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2783
+ vc.amount = self.amount
2784
+ vc.billingInfo = fieldSection.billing
2785
+ vc.additionalInfo = fieldSection.additional
2786
+ vc.visibility = fieldSection.visibility
2787
+ vc.easyPayDelegate = self.easyPayDelegate
2788
+ self.navigationController?.pushViewController(vc, animated: true)
2789
+ }
2790
+ }
2791
+ }
2792
+ }
2793
+ catch {
2794
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2795
+ }
2796
+ }
2448
2797
  }
2449
2798
  else {
2450
- grailPayNewAccountChargeApi()
2799
+ // Check if billing info data exists and is valid JSON without save
2800
+ if let billingInfoData = request.billingInfoData {
2801
+ do {
2802
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2803
+
2804
+ DispatchQueue.main.async {
2805
+
2806
+ if let billingInfoData = self.request.billingInfoData,
2807
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2808
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2809
+ print("Billing Info Data: \(jsonDict)")
2810
+
2811
+ // Redirect based on billing visibility
2812
+ if fieldSection.visibility.billing {
2813
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2814
+ vc.billingInfoData = billingInfoData
2815
+ vc.request = self.request
2816
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2817
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2818
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2819
+ vc.isSavedForFuture = self.isSavedForFuture
2820
+ vc.grailPayAccountID = self.newGrailPayAccountID
2821
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2822
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2823
+ vc.amount = self.amount
2824
+ vc.billingInfo = fieldSection.billing
2825
+ vc.additionalInfo = fieldSection.additional
2826
+ vc.visibility = fieldSection.visibility
2827
+ vc.easyPayDelegate = self.easyPayDelegate
2828
+ self.navigationController?.pushViewController(vc, animated: true)
2829
+ }
2830
+ else {
2831
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2832
+ vc.billingInfoData = billingInfoData
2833
+ vc.request = self.request
2834
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2835
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2836
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2837
+ vc.isSavedForFuture = self.isSavedForFuture
2838
+ vc.grailPayAccountID = self.newGrailPayAccountID
2839
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2840
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2841
+ vc.amount = self.amount
2842
+ vc.billingInfo = fieldSection.billing
2843
+ vc.additionalInfo = fieldSection.additional
2844
+ vc.visibility = fieldSection.visibility
2845
+ vc.easyPayDelegate = self.easyPayDelegate
2846
+ self.navigationController?.pushViewController(vc, animated: true)
2847
+ }
2848
+ }
2849
+ }
2850
+ }
2851
+ catch {
2852
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2853
+ }
2854
+ }
2855
+ else {
2856
+ // Proceed to call API if billing info not available
2857
+ grailPayNewAccountChargeApi()
2858
+ }
2451
2859
  }
2452
2860
  } else {
2453
2861
  grailPaySource = .newAccount
@@ -2468,30 +2876,30 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2468
2876
  case .success:
2469
2877
  if let chargeData = result.chargeData,
2470
2878
  let dataArray = chargeData["data"] as? [[String: Any]],
2471
- let firstAccount = dataArray.first {
2879
+ let selectedAccount = dataArray.first {
2472
2880
 
2473
- print("✅ Bank connected: \(firstAccount)")
2474
- self.selectedGrailPayAccountType = firstAccount["account_type"] as? String
2475
- self.selectedGrailPayAccountName = firstAccount["name"] as? String
2881
+ print("✅ Bank connected: \(selectedAccount)")
2882
+ self.selectedGrailPayAccountType = selectedAccount["account_type"] as? String
2883
+ self.selectedGrailPayAccountName = selectedAccount["name"] as? String
2476
2884
 
2477
2885
  if self.grailPaySource == .existingAccount {
2478
- self.accountConnectApi(account: firstAccount)
2886
+ self.accountConnectApi(account: selectedAccount)
2479
2887
  self.lblGrailPayAabandonError.text = "Default account successfully set"
2480
2888
  self.viewGrailPayAbandon.isHidden = false
2481
2889
  } else if self.grailPaySource == .newAccount {
2482
- self.newGrailPayAccountConnectApi(account: firstAccount)
2890
+ self.newGrailPayAccountConnectApi(account: selectedAccount)
2483
2891
  self.lblAbandonGrailPayNewAccountView.text = "Default account successfully set"
2484
2892
  self.viewAbandonGrailPayNewAccountView.isHidden = false
2485
2893
 
2486
- self.selectedNewGrailPayAccountType = firstAccount["account_type"] as? String
2487
- self.selectedNewGrailPayAccountName = firstAccount["name"] as? String
2894
+ self.selectedNewGrailPayAccountType = selectedAccount["account_type"] as? String
2895
+ self.selectedNewGrailPayAccountName = selectedAccount["name"] as? String
2488
2896
  }
2489
2897
 
2490
2898
  if self.selectedPaymentMethod == "Bank" {
2491
2899
  self.viewBtnShowSavedCards.isHidden = true
2492
2900
  }
2493
2901
 
2494
- let amountText = String(format: "$%.2f", self.request.amount)
2902
+ let amountText = String(format: "$%.2f", self.request.amount ?? 0)
2495
2903
  let submitText = self.request.submitButtonText
2496
2904
  let defaultTitle = (submitText?.isEmpty == false)
2497
2905
  ? "\(submitText!) (\(amountText))"
@@ -2571,7 +2979,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2571
2979
  "account_type": self.selectedGrailPayAccountType ?? "",
2572
2980
  "name": self.selectedGrailPayAccountName ?? "",
2573
2981
  "description": "payment checkout",
2574
- "email": "newmerchantadminuser12@test.com"
2982
+ "email": UserStoreSingleton.shared.merchantEmail ?? ""
2575
2983
  ]
2576
2984
 
2577
2985
  // Add these if recurring is enabled
@@ -2644,7 +3052,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2644
3052
  paymentDoneVC.chargeData = responseObject
2645
3053
  // Pass the selected payment method
2646
3054
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2647
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
3055
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3056
+ // Pass billingInfo and additionalInfo
3057
+ if let billingData = self.request.billingInfoData,
3058
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
3059
+
3060
+ // Extract main billing fields
3061
+ let cleanBillingInfo: [String: Any] = [
3062
+ "postal_code": billingInfoDict["postal_code"] ?? "",
3063
+ "country": billingInfoDict["country"] ?? "",
3064
+ "city": billingInfoDict["city"] ?? "",
3065
+ "address": billingInfoDict["address"] ?? "",
3066
+ "state": billingInfoDict["state"] ?? ""
3067
+ ]
3068
+ paymentDoneVC.billingInfo = cleanBillingInfo
3069
+
3070
+ // Extract additional_info
3071
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
3072
+ let cleanAdditionalInfo: [String: Any] = [
3073
+ "email": additional["email"] ?? "",
3074
+ "phone_number": additional["phone_number"] ?? "",
3075
+ "name": additional["name"] ?? "",
3076
+ "country_code": additional["country_code"] ?? ""
3077
+ ]
3078
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
3079
+ }
3080
+ }
2648
3081
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2649
3082
  }
2650
3083
  }
@@ -2775,140 +3208,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2775
3208
  paymentDoneVC.chargeData = responseObject
2776
3209
  // Pass the selected payment method
2777
3210
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2778
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
2779
- self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2780
- }
2781
- }
2782
- }
2783
- } else {
2784
- self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
2785
- }
2786
- } catch let jsonError {
2787
- self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
2788
- }
2789
- } else {
2790
- self.presentPaymentErrorVC(errorMessage: "No data received")
2791
- }
2792
- } else {
2793
- if let data = serviceData,
2794
- let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
2795
- let message = responseObj["message"] as? String {
2796
- self.presentPaymentErrorVC(errorMessage: message)
2797
- } else {
2798
- self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
2799
- }
2800
- }
2801
- }
2802
- task.resume()
2803
- }
2804
-
2805
- //MARK: - GrailPay New Account Banking Payment Charge Api with saving bank.
2806
- func grailPayNewAccountSavingChargeApi() {
2807
- showLoadingIndicator()
2808
- let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
2809
-
2810
- guard let serviceURL = URL(string: fullURL) else {
2811
- print("Invalid URL")
2812
- hideLoadingIndicator()
2813
- return
2814
- }
2815
-
2816
- var uRLRequest = URLRequest(url: serviceURL)
2817
- uRLRequest.httpMethod = "POST"
2818
- uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
2819
-
2820
- let token = UserStoreSingleton.shared.clientToken
2821
- print("Setting clientToken header: \(token ?? "None")")
2822
- uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
2823
-
2824
- if let apiKey = EnvironmentConfig.apiKey {
2825
- uRLRequest.addValue(apiKey, forHTTPHeaderField: "X-Api-Key")
2826
- }
2827
- if let apiSecret = EnvironmentConfig.apiSecret {
2828
- uRLRequest.addValue(apiSecret, forHTTPHeaderField: "X-Api-Secret")
2829
- }
2830
-
2831
- var params: [String: Any] = [
2832
- "account_id": self.newGrailPayAccountID ?? "",
2833
- "account_type": self.selectedNewGrailPayAccountType ?? "",
2834
- "name": self.selectedNewGrailPayAccountName ?? "",
2835
- "description": "payment checkout",
2836
- "customer_id": self.grailPayNewAccountCustomerID ?? "",
2837
- "save_account" : 1,
2838
- "is_default": 1
2839
- ]
2840
-
2841
- // Add these if recurring is enabled
2842
- if let req = request, req.is_recurring == true {
2843
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
2844
- // Only send start_date if type is .custom and field is not empty
2845
- if let startDateText = txtFieldSelectDateNewGrailPayBankView?.text, !startDateText.isEmpty {
2846
- let inputFormatter = DateFormatter()
2847
- inputFormatter.dateFormat = "dd/MM/yyyy"
2848
-
2849
- let outputFormatter = DateFormatter()
2850
- outputFormatter.dateFormat = "MM/dd/yyyy"
2851
-
2852
- if let date = inputFormatter.date(from: startDateText) {
2853
- let apiFormattedDate = outputFormatter.string(from: date)
2854
- params["start_date"] = apiFormattedDate
2855
- } else {
2856
- print("Invalid date format in startDateText")
2857
- }
2858
- }
2859
- }
2860
-
2861
- params["interval"] = txtFieldChosePlanNewGrailPayBankView.text.lowercased()
2862
- }
2863
-
2864
- print(params)
2865
-
2866
- do {
2867
- let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
2868
- uRLRequest.httpBody = jsonData
2869
- if let jsonString = String(data: jsonData, encoding: .utf8) {
2870
- print("JSON Payload: \(jsonString)")
2871
- }
2872
- } catch let error {
2873
- print("Error creating JSON data: \(error)")
2874
- hideLoadingIndicator()
2875
- return
2876
- }
2877
-
2878
- let session = URLSession.shared
2879
- let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
2880
-
2881
- DispatchQueue.main.async {
2882
- self.hideLoadingIndicator() // Stop loader when response is received
2883
- }
2884
-
2885
- if let error = error {
2886
- print("Error: \(error.localizedDescription)")
2887
- return
2888
- }
2889
-
2890
- guard let httpResponse = serviceResponse as? HTTPURLResponse else {
2891
- print("Invalid response")
2892
- return
2893
- }
2894
-
2895
- if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
2896
- if let data = serviceData {
2897
- do {
2898
- if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
2899
- print("Response Data: \(responseObject)")
2900
-
2901
- // Check if status is 0 and handle the error
2902
- if let status = responseObject["status"] as? Int, status == 0 {
2903
- let errorMessage = responseObject["message"] as? String ?? "Unknown error"
2904
- self.presentPaymentErrorVC(errorMessage: errorMessage)
2905
- } else {
2906
- DispatchQueue.main.async {
2907
- if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
2908
- paymentDoneVC.chargeData = responseObject
2909
- // Pass the selected payment method
2910
- paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2911
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
3211
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3212
+ // Pass billingInfo and additionalInfo
3213
+ if let billingData = self.request.billingInfoData,
3214
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
3215
+
3216
+ // Extract main billing fields
3217
+ let cleanBillingInfo: [String: Any] = [
3218
+ "postal_code": billingInfoDict["postal_code"] ?? "",
3219
+ "country": billingInfoDict["country"] ?? "",
3220
+ "city": billingInfoDict["city"] ?? "",
3221
+ "address": billingInfoDict["address"] ?? "",
3222
+ "state": billingInfoDict["state"] ?? ""
3223
+ ]
3224
+ paymentDoneVC.billingInfo = cleanBillingInfo
3225
+
3226
+ // Extract additional_info
3227
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
3228
+ let cleanAdditionalInfo: [String: Any] = [
3229
+ "email": additional["email"] ?? "",
3230
+ "phone_number": additional["phone_number"] ?? "",
3231
+ "name": additional["name"] ?? "",
3232
+ "country_code": additional["country_code"] ?? ""
3233
+ ]
3234
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
3235
+ }
3236
+ }
2912
3237
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2913
3238
  }
2914
3239
  }
@@ -3070,34 +3395,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3070
3395
  @IBAction func actionBtnNext(_ sender: UIButton) {
3071
3396
  // Check if billing info data exists and is valid JSON
3072
3397
  if let billingInfoData = request.billingInfoData {
3073
- DispatchQueue.global(qos: .userInitiated).async { [weak self] in
3074
- // Perform JSON parsing in a background thread
3075
- guard let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3076
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty else {
3077
- return
3078
- }
3398
+ do {
3399
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3079
3400
 
3080
3401
  DispatchQueue.main.async {
3081
- // Ensure UI updates happen on the main thread
3082
- guard let self = self else { return }
3083
-
3084
3402
  if self.selectedPaymentMethod == "Card" {
3085
- // Trim whitespace and newlines
3086
3403
  let cardNumber = self.cardNumberTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3087
3404
  let expiryDate = self.cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3088
3405
  let cvv = self.cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3089
3406
  let cardName = self.cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3090
-
3091
- // Remove spaces from card number for validation
3407
+ let email = self.txtFieldEmailCardView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3092
3408
  let sanitizedCardNumber = cardNumber.replacingOccurrences(of: " ", with: "")
3093
-
3094
- // Regular expression for expiry date format MM/yyyy
3095
3409
  let expiryDateRegex = #"^(0[1-9]|1[0-2])\/\d{4}$"#
3096
-
3097
- // Regular expression for a valid name (only letters and spaces)
3098
3410
  let nameRegex = #"^[A-Za-z\s]+$"#
3099
3411
 
3100
- // Validation checks
3101
3412
  if cardNumber.isEmpty {
3102
3413
  self.showAlert(title: "Missing Information", message: "Card Number is required.")
3103
3414
  return
@@ -3107,22 +3418,17 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3107
3418
  } else if expiryDate.isEmpty {
3108
3419
  self.showAlert(title: "Missing Information", message: "Card Expiry Date is required.")
3109
3420
  return
3110
- }
3111
- else if !expiryDate.matches(expiryDateRegex) {
3421
+ } else if !expiryDate.matches(expiryDateRegex) {
3112
3422
  self.showAlert(title: "Invalid Expiry Date", message: "Expiry Date must be in format MM/yyyy (e.g., 02/2026).")
3113
3423
  return
3114
- }
3115
- else {
3116
- // Check if expiry date is past tomorrow
3424
+ } else {
3117
3425
  let dateFormatter = DateFormatter()
3118
3426
  dateFormatter.dateFormat = "MM/yyyy"
3119
3427
  dateFormatter.timeZone = TimeZone.current
3120
3428
  if let expDate = dateFormatter.date(from: expiryDate) {
3121
3429
  let calendar = Calendar.current
3122
- // Get start of the month following expiry
3123
3430
  let expiryMonthStart = calendar.date(from: calendar.dateComponents([.year, .month], from: expDate))!
3124
3431
  let endOfMonth = calendar.date(byAdding: DateComponents(month: 1, day: -1), to: expiryMonthStart)!
3125
-
3126
3432
  let tomorrow = calendar.date(byAdding: .day, value: 1, to: Date())!
3127
3433
  if endOfMonth < tomorrow {
3128
3434
  self.showAlert(title: "Expired Card", message: "Card is expired or please enter a valid expiry date.")
@@ -3146,9 +3452,15 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3146
3452
  } else if !cardName.matches(nameRegex) {
3147
3453
  self.showAlert(title: "Invalid Name", message: "Name must contain only letters and spaces.")
3148
3454
  return
3455
+ } else if email.isEmpty {
3456
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3457
+ return
3458
+ } else if !self.isValidEmail(email) {
3459
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3460
+ return
3149
3461
  }
3150
3462
 
3151
- // Recurring Plan + Date Validation (only if is_recurring is true)
3463
+ // Recurring plan validation
3152
3464
  if let req = self.request, req.is_recurring == true {
3153
3465
  if self.txtFieldChosePlanCard.text.isEmpty {
3154
3466
  self.showAlert(title: "Missing Information", message: "Please choose your plan.")
@@ -3163,22 +3475,51 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3163
3475
  }
3164
3476
  }
3165
3477
 
3166
- // Proceed to BillingInfoVC
3167
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3168
- vc.billingInfoData = jsonDict
3169
- vc.cardNumber = cardNumber
3170
- vc.expiryDate = expiryDate
3171
- vc.cvv = cvv
3172
- vc.nameOnCard = cardName
3173
- vc.selectedPaymentMethod = self.selectedPaymentMethod
3174
- vc.isSavedForFuture = self.isSavedForFuture
3175
- vc.request = self.request
3176
- vc.chosenPlan = self.txtFieldChosePlanCard.text
3177
- vc.startDate = self.txtFieldStartDateCard.text
3178
- self.navigationController?.pushViewController(vc, animated: true)
3478
+ // Redirect based on billing visibility
3479
+ if fieldSection.visibility.billing {
3480
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3481
+ vc.billingInfoData = billingInfoData
3482
+ vc.cardNumber = cardNumber
3483
+ vc.expiryDate = expiryDate
3484
+ vc.cvv = cvv
3485
+ vc.nameOnCard = cardName
3486
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3487
+ vc.isSavedForFuture = self.isSavedForFuture
3488
+ vc.request = self.request
3489
+ vc.chosenPlan = self.txtFieldChosePlanCard.text
3490
+ vc.startDate = self.txtFieldStartDateCard.text
3491
+ vc.userEmail = self.txtFieldEmailCardView.text
3492
+ vc.amount = self.amount
3493
+ vc.billingInfo = fieldSection.billing
3494
+ vc.additionalInfo = fieldSection.additional
3495
+ vc.visibility = fieldSection.visibility
3496
+ vc.easyPayDelegate = self.easyPayDelegate
3497
+ self.navigationController?.pushViewController(vc, animated: true)
3498
+ } else {
3499
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
3500
+ vc.billingInfoData = billingInfoData
3501
+ vc.cardNumber = cardNumber
3502
+ vc.expiryDate = expiryDate
3503
+ vc.cvv = cvv
3504
+ vc.nameOnCard = cardName
3505
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3506
+ vc.isSavedForFuture = self.isSavedForFuture
3507
+ vc.request = self.request
3508
+ vc.chosenPlan = self.txtFieldChosePlanCard.text
3509
+ vc.startDate = self.txtFieldStartDateCard.text
3510
+ vc.userEmail = self.txtFieldEmailCardView.text
3511
+ vc.billingInfo = fieldSection.billing
3512
+ vc.additionalInfo = fieldSection.additional
3513
+ vc.amount = self.amount
3514
+ vc.visibility = fieldSection.visibility
3515
+ vc.easyPayDelegate = self.easyPayDelegate
3516
+ self.navigationController?.pushViewController(vc, animated: true)
3517
+ }
3179
3518
  }
3180
3519
  else if self.selectedPaymentMethod == "Bank" {
3181
3520
  // Bank Case
3521
+ let email = self.txtFieldEmailAccountView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3522
+
3182
3523
  if self.txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
3183
3524
  self.showAlert(title: "Missing Information", message: "Bank account name is required.")
3184
3525
  return
@@ -3205,6 +3546,14 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3205
3546
  self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3206
3547
  return
3207
3548
  }
3549
+ else if email.isEmpty {
3550
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3551
+ return
3552
+ } else if !self.isValidEmail(email) {
3553
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3554
+ return
3555
+ }
3556
+
3208
3557
  else if !self.agreeTermsAndCondtition {
3209
3558
  self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3210
3559
  return
@@ -3225,24 +3574,59 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3225
3574
  }
3226
3575
  }
3227
3576
 
3228
- // Proceed to BillingInfoVC
3229
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3230
- vc.accountName = self.txtFieldAccountName.text
3231
- vc.routingNumber = self.txtFieldRoutingNumber.text
3232
- vc.accountType = self.txtFieldAccountType.text
3233
- vc.accountNumber = self.txtFieldAccountNumber.text
3234
- vc.billingInfoData = jsonDict
3235
- vc.selectedPaymentMethod = self.selectedPaymentMethod
3236
- vc.isSavedForFuture = self.isSavedForFuture
3237
- vc.isFrom = "NormalBankPayWithoutSave"
3238
- vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3239
- vc.startDate = self.txtFieldSelectDateViewBankFields.text
3240
- vc.request = self.request
3241
- self.navigationController?.pushViewController(vc, animated: true)
3577
+ // Redirect based on billing visibility
3578
+ if fieldSection.visibility.billing {
3579
+ // Proceed to BillingInfoVC
3580
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3581
+ vc.accountName = self.txtFieldAccountName.text
3582
+ vc.routingNumber = self.txtFieldRoutingNumber.text
3583
+ vc.accountType = self.txtFieldAccountType.text
3584
+ vc.accountNumber = self.txtFieldAccountNumber.text
3585
+ // vc.billingInfoData = jsonDict
3586
+ vc.billingInfoData = billingInfoData
3587
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3588
+ vc.isSavedForFuture = self.isSavedForFuture
3589
+ vc.isFrom = "NormalBankPayWithoutSave"
3590
+ vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3591
+ vc.startDate = self.txtFieldSelectDateViewBankFields.text
3592
+ vc.request = self.request
3593
+ vc.userEmail = self.txtFieldEmailAccountView.text
3594
+ vc.amount = self.amount
3595
+ vc.billingInfo = fieldSection.billing
3596
+ vc.additionalInfo = fieldSection.additional
3597
+ vc.visibility = fieldSection.visibility
3598
+ vc.easyPayDelegate = self.easyPayDelegate
3599
+ self.navigationController?.pushViewController(vc, animated: true)
3600
+ }
3601
+ else {
3602
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
3603
+ vc.accountName = self.txtFieldAccountName.text
3604
+ vc.routingNumber = self.txtFieldRoutingNumber.text
3605
+ vc.accountType = self.txtFieldAccountType.text
3606
+ vc.accountNumber = self.txtFieldAccountNumber.text
3607
+ // vc.billingInfoData = jsonDict
3608
+ vc.billingInfoData = billingInfoData
3609
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3610
+ vc.isSavedForFuture = self.isSavedForFuture
3611
+ vc.isFrom = "NormalBankPayWithoutSave"
3612
+ vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3613
+ vc.startDate = self.txtFieldSelectDateViewBankFields.text
3614
+ vc.request = self.request
3615
+ vc.userEmail = self.txtFieldEmailAccountView.text
3616
+ vc.amount = self.amount
3617
+ vc.billingInfo = fieldSection.billing
3618
+ vc.additionalInfo = fieldSection.additional
3619
+ vc.visibility = fieldSection.visibility
3620
+ vc.easyPayDelegate = self.easyPayDelegate
3621
+ self.navigationController?.pushViewController(vc, animated: true)
3622
+ }
3242
3623
  }
3243
3624
  }
3625
+ } catch {
3626
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
3244
3627
  }
3245
- } else {
3628
+ }
3629
+ else {
3246
3630
  // Billing info is nil or empty
3247
3631
  if selectedPaymentMethod == "Card" {
3248
3632
  /// Card Case
@@ -3252,6 +3636,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3252
3636
  let expiryDate = self.cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3253
3637
  let cvv = self.cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3254
3638
  let cardName = self.cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3639
+ let email = self.txtFieldEmailCardView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3255
3640
 
3256
3641
  // Remove spaces from card number for validation
3257
3642
  let sanitizedCardNumber = cardNumber.replacingOccurrences(of: " ", with: "")
@@ -3312,6 +3697,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3312
3697
  self.showAlert(title: "Invalid Name", message: "Name must contain only letters and spaces.")
3313
3698
  return
3314
3699
  }
3700
+ else if email.isEmpty {
3701
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3702
+ return
3703
+ } else if !self.isValidEmail(email) {
3704
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3705
+ return
3706
+ }
3315
3707
 
3316
3708
  // Recurring Plan + Date Validation (only if is_recurring is true)
3317
3709
  if let req = self.request, req.is_recurring == true {
@@ -3332,7 +3724,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3332
3724
  if isSavedForFuture {
3333
3725
  navigateCardDataToEmailVerificationVC()
3334
3726
  } else {
3335
- if request.enable3DS == true {
3727
+ if request.secureAuthentication == true {
3336
3728
  threeDSecurePaymentApi()
3337
3729
  }
3338
3730
  else {
@@ -3342,6 +3734,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3342
3734
  }
3343
3735
  else if selectedPaymentMethod == "Bank" {
3344
3736
  // Bank Case
3737
+ let email = self.txtFieldEmailAccountView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3738
+
3345
3739
  if txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
3346
3740
  showAlert(title: "Missing Information", message: "Bank account name is required.")
3347
3741
  return
@@ -3370,6 +3764,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3370
3764
  self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3371
3765
  return
3372
3766
  }
3767
+ else if email.isEmpty {
3768
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3769
+ return
3770
+ } else if !self.isValidEmail(email) {
3771
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3772
+ return
3773
+ }
3373
3774
  else if !agreeTermsAndCondtition {
3374
3775
  showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3375
3776
  return
@@ -3452,10 +3853,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3452
3853
  if selectedPaymentMethod == "Card" {
3453
3854
  self.viewSingleSavedAccount.isHidden = true
3454
3855
  self.viewBankFields.isHidden = true
3455
- self.viewBtnShowSavedCards.isHidden = false
3456
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
3457
- self.viewBtnShowSavedCardHeight.constant = 50
3458
- self.viewBtnShowSavedCardTopCon.constant = 20
3856
+ // self.viewBtnShowSavedCards.isHidden = false
3857
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
3858
+ // self.viewBtnShowSavedCardHeight.constant = 50
3859
+ // self.viewBtnShowSavedCardTopCon.constant = 20
3860
+
3861
+ if request.saveCard == false {
3862
+ self.viewBtnShowSavedCards.isHidden = true
3863
+ self.viewBtnShowSavedCardHeight.constant = 0
3864
+ self.viewBtnShowSavedCardTopCon.constant = 0
3865
+ }
3866
+ else {
3867
+ self.viewBtnShowSavedCards.isHidden = false
3868
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
3869
+ self.viewBtnShowSavedCardHeight.constant = 50
3870
+ self.viewBtnShowSavedCardTopCon.constant = 20
3871
+ }
3872
+
3459
3873
  self.OTPView.isHidden = true
3460
3874
  self.emailView.isHidden = true
3461
3875
  self.viewCardFields.isHidden = false
@@ -3471,10 +3885,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3471
3885
  }
3472
3886
  else if selectedPaymentMethod == "Bank" {
3473
3887
  self.viewBankFields.isHidden = false
3474
- self.viewBtnShowSavedCards.isHidden = false
3475
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3476
- self.viewBtnShowSavedCardHeight.constant = 50
3477
- self.viewBtnShowSavedCardTopCon.constant = 20
3888
+ // self.viewBtnShowSavedCards.isHidden = false
3889
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3890
+ // self.viewBtnShowSavedCardHeight.constant = 50
3891
+ // self.viewBtnShowSavedCardTopCon.constant = 20
3892
+
3893
+ if request.saveAccount == false {
3894
+ self.viewBtnShowSavedCards.isHidden = true
3895
+ self.viewBtnShowSavedCardHeight.constant = 0
3896
+ self.viewBtnShowSavedCardTopCon.constant = 0
3897
+ }
3898
+ else {
3899
+ self.viewBtnShowSavedCards.isHidden = false
3900
+ self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3901
+ self.viewBtnShowSavedCardHeight.constant = 50
3902
+ self.viewBtnShowSavedCardTopCon.constant = 20
3903
+ }
3904
+
3478
3905
  self.OTPView.isHidden = true
3479
3906
  self.emailView.isHidden = true
3480
3907
  self.viewCardFields.isHidden = true
@@ -3618,42 +4045,80 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3618
4045
  grailPayAaccountChargeSingleSavedAccountApi()
3619
4046
  } else {
3620
4047
  // Check if billingInfoData is not nil or empty
3621
- if let billingInfoData = request.billingInfoData,
3622
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3623
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
3624
-
3625
- // Recurring Plan + Date Validation (only if is_recurring is true)
3626
- if let req = self.request, req.is_recurring == true {
3627
- if txtFieldSelectPlanSingleSavedBankView.text.isEmpty {
3628
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
3629
- return
3630
- }
4048
+ if let billingInfoData = request.billingInfoData {
4049
+ do {
4050
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3631
4051
 
3632
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
3633
- if txtFieldSelectDateSingleSavedBankView.text.isEmpty {
3634
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
3635
- return
4052
+ DispatchQueue.main.async {
4053
+
4054
+ if let billingInfoData = self.request.billingInfoData,
4055
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4056
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4057
+
4058
+ // Recurring Plan + Date Validation (only if is_recurring is true)
4059
+ if let req = self.request, req.is_recurring == true {
4060
+ if self.txtFieldSelectPlanSingleSavedBankView.text.isEmpty {
4061
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
4062
+ return
4063
+ }
4064
+
4065
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
4066
+ if self.txtFieldSelectDateSingleSavedBankView.text.isEmpty {
4067
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
4068
+ return
4069
+ }
4070
+ }
4071
+ }
4072
+
4073
+ // Check if the terms and conditions are agreed
4074
+ if !self.agreeTermsAndCondtition {
4075
+ self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
4076
+ return
4077
+ }
4078
+
4079
+ // Redirect based on billing visibility
4080
+ if fieldSection.visibility.billing {
4081
+ // Proceed with the Pay Now action
4082
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
4083
+ // Pass the customer_id and account_id to BillingInfoVC
4084
+ vc.customerID = self.selectedbankAccounts?.customer_id
4085
+ vc.accountID = self.selectedbankAccounts?.account_id
4086
+ vc.billingInfoData = billingInfoData
4087
+ vc.isFrom = "SavedBank"
4088
+ vc.selectedPaymentMethod = "Bank"
4089
+ vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
4090
+ vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
4091
+ vc.request = self.request
4092
+ vc.amount = self.amount
4093
+ vc.billingInfo = fieldSection.billing
4094
+ vc.additionalInfo = fieldSection.additional
4095
+ vc.visibility = fieldSection.visibility
4096
+ vc.easyPayDelegate = self.easyPayDelegate
4097
+ self.navigationController?.pushViewController(vc, animated: true)
4098
+ }
4099
+ else {
4100
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
4101
+ vc.customerID = self.selectedbankAccounts?.customer_id
4102
+ vc.accountID = self.selectedbankAccounts?.account_id
4103
+ vc.billingInfoData = billingInfoData
4104
+ vc.isFrom = "SavedBank"
4105
+ vc.selectedPaymentMethod = "Bank"
4106
+ vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
4107
+ vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
4108
+ vc.request = self.request
4109
+ vc.amount = self.amount
4110
+ vc.billingInfo = fieldSection.billing
4111
+ vc.additionalInfo = fieldSection.additional
4112
+ vc.visibility = fieldSection.visibility
4113
+ vc.easyPayDelegate = self.easyPayDelegate
4114
+ self.navigationController?.pushViewController(vc, animated: true)
4115
+ }
3636
4116
  }
3637
4117
  }
3638
4118
  }
3639
-
3640
- // Check if the terms and conditions are agreed
3641
- if !agreeTermsAndCondtition {
3642
- showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3643
- return
4119
+ catch {
4120
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
3644
4121
  }
3645
- // Proceed with the Pay Now action
3646
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3647
- // Pass the customer_id and account_id to BillingInfoVC
3648
- vc.customerID = selectedbankAccounts?.customer_id
3649
- vc.accountID = selectedbankAccounts?.account_id
3650
- vc.billingInfoData = jsonDict
3651
- vc.isFrom = "SavedBank"
3652
- vc.selectedPaymentMethod = "Bank"
3653
- vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
3654
- vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
3655
- vc.request = self.request
3656
- self.navigationController?.pushViewController(vc, animated: true)
3657
4122
  }
3658
4123
  else {
3659
4124
  //If Billing info is nil or empty
@@ -3701,72 +4166,115 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3701
4166
 
3702
4167
  @IBAction func actionBtnPayNowNewAccountView(_ sender: UIButton) {
3703
4168
  // Check if billingInfoData is not nil or empty
3704
- if let billingInfoData = request.billingInfoData,
3705
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3706
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
3707
- print("Billing Info Data: \(jsonDict)")
3708
-
3709
- // Retrieve and trim text field values (removing leading and trailing whitespace)
3710
- let accountName = txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3711
- let routingNumber = txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3712
- let accountType = txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3713
- let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3714
- let confirmAccountNumber = txtFieldConfirmAccountNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3715
-
3716
- // Check if any field is empty
3717
- if accountName.isEmpty || routingNumber.isEmpty || accountType.isEmpty || accountNumber.isEmpty || confirmAccountNumber.isEmpty {
3718
- let alert = UIAlertController(title: "Missing Information", message: "Please fill in all bank details.", preferredStyle: .alert)
3719
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
3720
- self.present(alert, animated: true, completion: nil)
3721
- return
3722
- }
3723
-
3724
- // Check if routing number is exactly 9 digits and numeric
3725
- if routingNumber.count != 9 || !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: routingNumber)) {
3726
- self.showAlert(title: "Invalid Routing Number", message: "Routing number is not correct. It must be exactly 9 digits.")
3727
- return
3728
- }
3729
-
3730
- // Check if account number and confirmation match
3731
- if accountNumber != confirmAccountNumber {
3732
- self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3733
- return
3734
- }
3735
-
3736
- // Recurring Plan + Date Validation (only if is_recurring is true)
3737
- if let req = self.request, req.is_recurring == true {
3738
- if txtFieldSelectPlanNewAccountView.text.isEmpty {
3739
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
3740
- return
3741
- }
4169
+ if let billingInfoData = request.billingInfoData {
4170
+ do {
4171
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3742
4172
 
3743
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
3744
- if txtFieldSelectDateNewAccountView.text.isEmpty {
3745
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
3746
- return
4173
+ DispatchQueue.main.async {
4174
+
4175
+ if let billingInfoData = self.request.billingInfoData,
4176
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4177
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4178
+ print("Billing Info Data: \(jsonDict)")
4179
+
4180
+ // Retrieve and trim text field values (removing leading and trailing whitespace)
4181
+ let accountName = self.txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4182
+ let routingNumber = self.txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4183
+ let accountType = self.txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4184
+ let accountNumber = self.txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4185
+ let confirmAccountNumber = self.txtFieldConfirmAccountNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4186
+
4187
+ // Check if any field is empty
4188
+ if accountName.isEmpty || routingNumber.isEmpty || accountType.isEmpty || accountNumber.isEmpty || confirmAccountNumber.isEmpty {
4189
+ let alert = UIAlertController(title: "Missing Information", message: "Please fill in all bank details.", preferredStyle: .alert)
4190
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
4191
+ self.present(alert, animated: true, completion: nil)
4192
+ return
4193
+ }
4194
+
4195
+ // Check if routing number is exactly 9 digits and numeric
4196
+ if routingNumber.count != 9 || !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: routingNumber)) {
4197
+ self.showAlert(title: "Invalid Routing Number", message: "Routing number is not correct. It must be exactly 9 digits.")
4198
+ return
4199
+ }
4200
+
4201
+ // Check if account number and confirmation match
4202
+ if accountNumber != confirmAccountNumber {
4203
+ self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
4204
+ return
4205
+ }
4206
+
4207
+ // Recurring Plan + Date Validation (only if is_recurring is true)
4208
+ if let req = self.request, req.is_recurring == true {
4209
+ if self.txtFieldSelectPlanNewAccountView.text.isEmpty {
4210
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
4211
+ return
4212
+ }
4213
+
4214
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
4215
+ if self.txtFieldSelectDateNewAccountView.text.isEmpty {
4216
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
4217
+ return
4218
+ }
4219
+ }
4220
+ }
4221
+
4222
+ // Determine the vc.isFrom value based on isSavedNewAccount
4223
+ let isSavedNewAccount = self.isSavedNewAccount
4224
+ let isFromValue = isSavedNewAccount ? "AddNewAccountWithSave" : "AddNewAccountWithoutSave"
4225
+
4226
+ // Redirect based on billing visibility
4227
+ if fieldSection.visibility.billing {
4228
+ // Proceed with the Pay Now action
4229
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
4230
+ vc.accountName = accountName
4231
+ vc.routingNumber = routingNumber
4232
+ vc.accountType = accountType
4233
+ vc.accountNumber = accountNumber
4234
+ vc.billingInfoData = billingInfoData
4235
+ vc.selectedPaymentMethod = "Bank"
4236
+ vc.isFrom = isFromValue
4237
+ vc.isSavedNewAccount = isSavedNewAccount
4238
+ vc.delegate = self
4239
+ vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
4240
+ vc.startDate = self.txtFieldSelectDateNewAccountView.text
4241
+ vc.request = self.request
4242
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
4243
+ vc.amount = self.amount
4244
+ vc.billingInfo = fieldSection.billing
4245
+ vc.additionalInfo = fieldSection.additional
4246
+ vc.visibility = fieldSection.visibility
4247
+ vc.easyPayDelegate = self.easyPayDelegate
4248
+ self.navigationController?.pushViewController(vc, animated: true)
4249
+ }
4250
+ else {
4251
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
4252
+ vc.accountName = accountName
4253
+ vc.routingNumber = routingNumber
4254
+ vc.accountType = accountType
4255
+ vc.accountNumber = accountNumber
4256
+ vc.billingInfoData = billingInfoData
4257
+ vc.selectedPaymentMethod = "Bank"
4258
+ vc.isFrom = isFromValue
4259
+ vc.isSavedNewAccount = isSavedNewAccount
4260
+ // vc.delegate = self
4261
+ vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
4262
+ vc.startDate = self.txtFieldSelectDateNewAccountView.text
4263
+ vc.request = self.request
4264
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
4265
+ vc.amount = self.amount
4266
+ vc.billingInfo = fieldSection.billing
4267
+ vc.additionalInfo = fieldSection.additional
4268
+ vc.visibility = fieldSection.visibility
4269
+ vc.easyPayDelegate = self.easyPayDelegate
4270
+ self.navigationController?.pushViewController(vc, animated: true)
4271
+ }
3747
4272
  }
3748
4273
  }
3749
4274
  }
3750
-
3751
- // Determine the vc.isFrom value based on isSavedNewAccount
3752
- let isSavedNewAccount = isSavedNewAccount
3753
- let isFromValue = isSavedNewAccount ? "AddNewAccountWithSave" : "AddNewAccountWithoutSave"
3754
-
3755
- // Proceed with the Pay Now action
3756
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3757
- vc.accountName = accountName
3758
- vc.routingNumber = routingNumber
3759
- vc.accountType = accountType
3760
- vc.accountNumber = accountNumber
3761
- vc.billingInfoData = jsonDict
3762
- vc.selectedPaymentMethod = "Bank"
3763
- vc.isFrom = isFromValue
3764
- vc.isSavedNewAccount = isSavedNewAccount
3765
- vc.delegate = self
3766
- vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
3767
- vc.startDate = self.txtFieldSelectDateNewAccountView.text
3768
- vc.request = self.request
3769
- self.navigationController?.pushViewController(vc, animated: true)
4275
+ catch {
4276
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
4277
+ }
3770
4278
  }
3771
4279
  else {
3772
4280
  //If Billing info is nil or empty
@@ -4481,6 +4989,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4481
4989
  paymentDoneVC.chargeData = responseObject
4482
4990
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4483
4991
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
4992
+
4993
+ // Pass billingInfo and additionalInfo
4994
+ if let billingData = self.request.billingInfoData,
4995
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
4996
+
4997
+ // Extract main billing fields
4998
+ let cleanBillingInfo: [String: Any] = [
4999
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5000
+ "country": billingInfoDict["country"] ?? "",
5001
+ "city": billingInfoDict["city"] ?? "",
5002
+ "address": billingInfoDict["address"] ?? "",
5003
+ "state": billingInfoDict["state"] ?? ""
5004
+ ]
5005
+ paymentDoneVC.billingInfo = cleanBillingInfo
5006
+
5007
+ // Extract additional_info
5008
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5009
+ let cleanAdditionalInfo: [String: Any] = [
5010
+ "email": additional["email"] ?? "",
5011
+ "phone_number": additional["phone_number"] ?? "",
5012
+ "name": additional["name"] ?? "",
5013
+ "country_code": additional["country_code"] ?? ""
5014
+ ]
5015
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5016
+ }
5017
+ }
4484
5018
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4485
5019
  }
4486
5020
  }
@@ -4538,24 +5072,6 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4538
5072
  uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
4539
5073
  }
4540
5074
 
4541
- ///OLD Params
4542
- // // Prepare parameters
4543
- // let email = UserStoreSingleton.shared.verificationEmail ?? ""
4544
- // let namePart = email.split(separator: "@").first.map(String.init) ?? ""
4545
- //
4546
- // var params: [String: Any] = [
4547
- // "name": namePart,
4548
- // "email": email,
4549
- // "description": "TestDescription",
4550
- // "currency": "usd",
4551
- // "payment_method": "card",
4552
- // "save_card": 0,
4553
- // "customer": selectedCard?.customerId ?? "",
4554
- // "card_id": selectedCard?.cardId ?? "",
4555
- // "cvc": txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "",
4556
- // "customer_id": selectedCard?.customerId ?? ""
4557
- // ]
4558
-
4559
5075
  var params: [String: Any] = [
4560
5076
  "description": "payment checkout",
4561
5077
  "currency": "usd",
@@ -4633,6 +5149,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4633
5149
  paymentDoneVC.chargeData = responseObject
4634
5150
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4635
5151
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5152
+
5153
+ // Pass billingInfo and additionalInfo
5154
+ if let billingData = self.request.billingInfoData,
5155
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5156
+
5157
+ // Extract main billing fields
5158
+ let cleanBillingInfo: [String: Any] = [
5159
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5160
+ "country": billingInfoDict["country"] ?? "",
5161
+ "city": billingInfoDict["city"] ?? "",
5162
+ "address": billingInfoDict["address"] ?? "",
5163
+ "state": billingInfoDict["state"] ?? ""
5164
+ ]
5165
+ paymentDoneVC.billingInfo = cleanBillingInfo
5166
+
5167
+ // Extract additional_info
5168
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5169
+ let cleanAdditionalInfo: [String: Any] = [
5170
+ "email": additional["email"] ?? "",
5171
+ "phone_number": additional["phone_number"] ?? "",
5172
+ "name": additional["name"] ?? "",
5173
+ "country_code": additional["country_code"] ?? ""
5174
+ ]
5175
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5176
+ }
5177
+ }
4636
5178
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4637
5179
  }
4638
5180
  }
@@ -4851,6 +5393,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4851
5393
  paymentDoneVC.chargeData = responseObject
4852
5394
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4853
5395
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5396
+ // Pass billingInfo and additionalInfo
5397
+ if let billingData = self.request.billingInfoData,
5398
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5399
+
5400
+ // Extract main billing fields
5401
+ let cleanBillingInfo: [String: Any] = [
5402
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5403
+ "country": billingInfoDict["country"] ?? "",
5404
+ "city": billingInfoDict["city"] ?? "",
5405
+ "address": billingInfoDict["address"] ?? "",
5406
+ "state": billingInfoDict["state"] ?? ""
5407
+ ]
5408
+ paymentDoneVC.billingInfo = cleanBillingInfo
5409
+
5410
+ // Extract additional_info
5411
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5412
+ let cleanAdditionalInfo: [String: Any] = [
5413
+ "email": additional["email"] ?? "",
5414
+ "phone_number": additional["phone_number"] ?? "",
5415
+ "name": additional["name"] ?? "",
5416
+ "country_code": additional["country_code"] ?? ""
5417
+ ]
5418
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5419
+ }
5420
+ }
4854
5421
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4855
5422
  }
4856
5423
  }
@@ -5384,7 +5951,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5384
5951
  paymentDoneVC.chargeData = responseObject
5385
5952
  // Pass the selected payment method
5386
5953
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5387
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
5954
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5955
+ // Pass billingInfo and additionalInfo
5956
+ if let billingData = self.request.billingInfoData,
5957
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5958
+
5959
+ // Extract main billing fields
5960
+ let cleanBillingInfo: [String: Any] = [
5961
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5962
+ "country": billingInfoDict["country"] ?? "",
5963
+ "city": billingInfoDict["city"] ?? "",
5964
+ "address": billingInfoDict["address"] ?? "",
5965
+ "state": billingInfoDict["state"] ?? ""
5966
+ ]
5967
+ paymentDoneVC.billingInfo = cleanBillingInfo
5968
+
5969
+ // Extract additional_info
5970
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5971
+ let cleanAdditionalInfo: [String: Any] = [
5972
+ "email": additional["email"] ?? "",
5973
+ "phone_number": additional["phone_number"] ?? "",
5974
+ "name": additional["name"] ?? "",
5975
+ "country_code": additional["country_code"] ?? ""
5976
+ ]
5977
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5978
+ }
5979
+ }
5388
5980
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5389
5981
  }
5390
5982
  }
@@ -5516,7 +6108,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5516
6108
  paymentDoneVC.chargeData = responseObject
5517
6109
  // Pass the selected payment method
5518
6110
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5519
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
6111
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6112
+ // Pass billingInfo and additionalInfo
6113
+ if let billingData = self.request.billingInfoData,
6114
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6115
+
6116
+ // Extract main billing fields
6117
+ let cleanBillingInfo: [String: Any] = [
6118
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6119
+ "country": billingInfoDict["country"] ?? "",
6120
+ "city": billingInfoDict["city"] ?? "",
6121
+ "address": billingInfoDict["address"] ?? "",
6122
+ "state": billingInfoDict["state"] ?? ""
6123
+ ]
6124
+ paymentDoneVC.billingInfo = cleanBillingInfo
6125
+
6126
+ // Extract additional_info
6127
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6128
+ let cleanAdditionalInfo: [String: Any] = [
6129
+ "email": additional["email"] ?? "",
6130
+ "phone_number": additional["phone_number"] ?? "",
6131
+ "name": additional["name"] ?? "",
6132
+ "country_code": additional["country_code"] ?? ""
6133
+ ]
6134
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6135
+ }
6136
+ }
5520
6137
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5521
6138
  }
5522
6139
  }
@@ -5658,7 +6275,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5658
6275
  paymentDoneVC.chargeData = responseObject
5659
6276
  // Pass the selected payment method
5660
6277
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5661
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
6278
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6279
+ // Pass billingInfo and additionalInfo
6280
+ if let billingData = self.request.billingInfoData,
6281
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6282
+
6283
+ // Extract main billing fields
6284
+ let cleanBillingInfo: [String: Any] = [
6285
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6286
+ "country": billingInfoDict["country"] ?? "",
6287
+ "city": billingInfoDict["city"] ?? "",
6288
+ "address": billingInfoDict["address"] ?? "",
6289
+ "state": billingInfoDict["state"] ?? ""
6290
+ ]
6291
+ paymentDoneVC.billingInfo = cleanBillingInfo
6292
+
6293
+ // Extract additional_info
6294
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6295
+ let cleanAdditionalInfo: [String: Any] = [
6296
+ "email": additional["email"] ?? "",
6297
+ "phone_number": additional["phone_number"] ?? "",
6298
+ "name": additional["name"] ?? "",
6299
+ "country_code": additional["country_code"] ?? ""
6300
+ ]
6301
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6302
+ }
6303
+ }
5662
6304
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5663
6305
  }
5664
6306
  }
@@ -5811,6 +6453,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5811
6453
  paymentDoneVC.chargeData = responseObject
5812
6454
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5813
6455
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6456
+ // Pass billingInfo and additionalInfo
6457
+ if let billingData = self.request.billingInfoData,
6458
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6459
+
6460
+ // Extract main billing fields
6461
+ let cleanBillingInfo: [String: Any] = [
6462
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6463
+ "country": billingInfoDict["country"] ?? "",
6464
+ "city": billingInfoDict["city"] ?? "",
6465
+ "address": billingInfoDict["address"] ?? "",
6466
+ "state": billingInfoDict["state"] ?? ""
6467
+ ]
6468
+ paymentDoneVC.billingInfo = cleanBillingInfo
6469
+
6470
+ // Extract additional_info
6471
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6472
+ let cleanAdditionalInfo: [String: Any] = [
6473
+ "email": additional["email"] ?? "",
6474
+ "phone_number": additional["phone_number"] ?? "",
6475
+ "name": additional["name"] ?? "",
6476
+ "country_code": additional["country_code"] ?? ""
6477
+ ]
6478
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6479
+ }
6480
+ }
5814
6481
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5815
6482
  }
5816
6483
  }
@@ -6198,6 +6865,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6198
6865
  params["interval"] = txtFieldChosePlanCard.text.lowercased()
6199
6866
  }
6200
6867
 
6868
+ print(params)
6869
+
6201
6870
  do {
6202
6871
  let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
6203
6872
  uRLRequest.httpBody = jsonData
@@ -6245,7 +6914,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6245
6914
  paymentDoneVC.redirectURL = urlString
6246
6915
  paymentDoneVC.chargeData = responseObject
6247
6916
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6248
-
6917
+ // Pass billingInfo and additionalInfo
6918
+ if let billingData = self.request.billingInfoData,
6919
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6920
+
6921
+ // Extract main billing fields
6922
+ let cleanBillingInfo: [String: Any] = [
6923
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6924
+ "country": billingInfoDict["country"] ?? "",
6925
+ "city": billingInfoDict["city"] ?? "",
6926
+ "address": billingInfoDict["address"] ?? "",
6927
+ "state": billingInfoDict["state"] ?? ""
6928
+ ]
6929
+ paymentDoneVC.billingInfo = cleanBillingInfo
6930
+
6931
+ // Extract additional_info
6932
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6933
+ let cleanAdditionalInfo: [String: Any] = [
6934
+ "email": additional["email"] ?? "",
6935
+ "phone_number": additional["phone_number"] ?? "",
6936
+ "name": additional["name"] ?? "",
6937
+ "country_code": additional["country_code"] ?? ""
6938
+ ]
6939
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6940
+ }
6941
+ }
6249
6942
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
6250
6943
  }
6251
6944
  }
@@ -6455,7 +7148,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6455
7148
  paymentDoneVC.redirectURL = urlString
6456
7149
  paymentDoneVC.chargeData = responseObject
6457
7150
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6458
-
7151
+ // Pass billingInfo and additionalInfo
7152
+ if let billingData = self.request.billingInfoData,
7153
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
7154
+
7155
+ // Extract main billing fields
7156
+ let cleanBillingInfo: [String: Any] = [
7157
+ "postal_code": billingInfoDict["postal_code"] ?? "",
7158
+ "country": billingInfoDict["country"] ?? "",
7159
+ "city": billingInfoDict["city"] ?? "",
7160
+ "address": billingInfoDict["address"] ?? "",
7161
+ "state": billingInfoDict["state"] ?? ""
7162
+ ]
7163
+ paymentDoneVC.billingInfo = cleanBillingInfo
7164
+
7165
+ // Extract additional_info
7166
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
7167
+ let cleanAdditionalInfo: [String: Any] = [
7168
+ "email": additional["email"] ?? "",
7169
+ "phone_number": additional["phone_number"] ?? "",
7170
+ "name": additional["name"] ?? "",
7171
+ "country_code": additional["country_code"] ?? ""
7172
+ ]
7173
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
7174
+ }
7175
+ }
6459
7176
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
6460
7177
  }
6461
7178
  }
@@ -6531,20 +7248,6 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6531
7248
  }
6532
7249
  }
6533
7250
 
6534
- // // Update border color based on selection
6535
- // if selectedIndex == indexPath {
6536
- // if let primaryBackGroundColor = UserStoreSingleton.shared.primary_btn_bg_col,
6537
- // let uiColor = UIColor(hex: primaryBackGroundColor) {
6538
- // cell.vwMain.layer.borderColor = uiColor.cgColor // Convert UIColor to CGColor
6539
- // cell.imgVwPayments.tintColor = uiColor
6540
- // cell.lblPayment.textColor = uiColor
6541
- // }
6542
- // } else {
6543
- // cell.vwMain.layer.borderColor = UIColor.gray.cgColor
6544
- // cell.imgVwPayments.tintColor = .systemGray
6545
- // cell.lblPayment.textColor = .systemGray
6546
- // }
6547
-
6548
7251
  return cell
6549
7252
  }
6550
7253
 
@@ -6596,10 +7299,23 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6596
7299
  if UserStoreSingleton.shared.isLoggedIn == false {
6597
7300
  self.viewSingleSavedAccount.isHidden = true
6598
7301
  self.viewBankFields.isHidden = true
6599
- self.viewBtnShowSavedCards.isHidden = false
6600
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
6601
- self.viewBtnShowSavedCardHeight.constant = 50
6602
- self.viewBtnShowSavedCardTopCon.constant = 20
7302
+ // self.viewBtnShowSavedCards.isHidden = false
7303
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
7304
+ // self.viewBtnShowSavedCardHeight.constant = 50
7305
+ // self.viewBtnShowSavedCardTopCon.constant = 20
7306
+
7307
+ if request.saveCard == false {
7308
+ self.viewBtnShowSavedCards.isHidden = true
7309
+ self.viewBtnShowSavedCardHeight.constant = 0
7310
+ self.viewBtnShowSavedCardTopCon.constant = 0
7311
+ }
7312
+ else {
7313
+ self.viewBtnShowSavedCards.isHidden = false
7314
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
7315
+ self.viewBtnShowSavedCardHeight.constant = 50
7316
+ self.viewBtnShowSavedCardTopCon.constant = 20
7317
+ }
7318
+
6603
7319
  self.btnShowSavedCard.isHidden = false
6604
7320
  self.OTPView.isHidden = true
6605
7321
  self.emailView.isHidden = true
@@ -6669,10 +7385,23 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6669
7385
  case "Bank":
6670
7386
  if UserStoreSingleton.shared.isLoggedIn == false {
6671
7387
  // self.viewBankFields.isHidden = false
6672
- self.viewBtnShowSavedCards.isHidden = false
6673
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
6674
- self.viewBtnShowSavedCardHeight.constant = 50
6675
- self.viewBtnShowSavedCardTopCon.constant = 20
7388
+ // self.viewBtnShowSavedCards.isHidden = false
7389
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
7390
+ // self.viewBtnShowSavedCardHeight.constant = 50
7391
+ // self.viewBtnShowSavedCardTopCon.constant = 20
7392
+
7393
+ if request.saveAccount == false {
7394
+ self.viewBtnShowSavedCards.isHidden = true
7395
+ self.viewBtnShowSavedCardHeight.constant = 0
7396
+ self.viewBtnShowSavedCardTopCon.constant = 0
7397
+ }
7398
+ else {
7399
+ self.viewBtnShowSavedCards.isHidden = false
7400
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
7401
+ self.viewBtnShowSavedCardHeight.constant = 50
7402
+ self.viewBtnShowSavedCardTopCon.constant = 20
7403
+ }
7404
+
6676
7405
  self.OTPView.isHidden = true
6677
7406
  self.emailView.isHidden = true
6678
7407
  self.viewCardFields.isHidden = true
@@ -7481,6 +8210,13 @@ extension PaymentInfoVC: UITextFieldDelegate {
7481
8210
  } else {
7482
8211
  viewTxtFieldNameOnCard.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
7483
8212
  }
8213
+ } else if textField == txtFieldEmailCardView.textField {
8214
+ if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
8215
+ let uiColor = UIColor(hex: primaryBtnFontColor) {
8216
+ viewTxtFieldEmailCardView.layer.borderColor = uiColor.cgColor
8217
+ } else {
8218
+ viewTxtFieldEmailCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
8219
+ }
7484
8220
  }
7485
8221
  else if textField == txtFieldEmail {
7486
8222
  if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
@@ -7598,6 +8334,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7598
8334
  viewTextFieldConfirmAccount.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
7599
8335
  }
7600
8336
  }
8337
+ else if textField == txtFieldEmailAccountView.textField {
8338
+ if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
8339
+ let uiColor = UIColor(hex: primaryBtnFontColor) {
8340
+ viewTxtFieldEmailAccountView.layer.borderColor = uiColor.cgColor
8341
+ } else {
8342
+ viewTxtFieldEmailAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
8343
+ }
8344
+ }
7601
8345
  //New Bank Account View
7602
8346
  else if textField == txtFieldAccountNameNewAccountView {
7603
8347
  if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
@@ -7674,6 +8418,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7674
8418
  viewTxtFieldNameOnCard.layer.borderColor = UIColor.systemGray.cgColor
7675
8419
  }
7676
8420
  }
8421
+ else if textField == txtFieldEmailCardView.textField {
8422
+ if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
8423
+ let borderColor = UIColor(hex: bodyBackgroundColor) {
8424
+ viewTxtFieldEmailCardView.layer.borderColor = borderColor.cgColor
8425
+ } else {
8426
+ viewTxtFieldEmailCardView.layer.borderColor = UIColor.systemGray.cgColor
8427
+ }
8428
+ }
7677
8429
  else if textField == txtFieldEmail {
7678
8430
  if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
7679
8431
  let borderColor = UIColor(hex: bodyBackgroundColor) {
@@ -7789,6 +8541,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7789
8541
  viewTextFieldConfirmAccount.layer.borderColor = UIColor.systemGray.cgColor
7790
8542
  }
7791
8543
  }
8544
+ else if textField == txtFieldEmailAccountView.textField {
8545
+ if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
8546
+ let borderColor = UIColor(hex: bodyBackgroundColor) {
8547
+ viewTxtFieldEmailAccountView.layer.borderColor = borderColor.cgColor
8548
+ } else {
8549
+ viewTxtFieldEmailAccountView.layer.borderColor = UIColor.systemGray.cgColor
8550
+ }
8551
+ }
7792
8552
  //New Bank Account View
7793
8553
  else if textField == txtFieldAccountNameNewAccountView {
7794
8554
  if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,