@jimrising/easymerchantsdk-react-native 2.3.3 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Add the EasyMerchant SDK to your `package.json` under `dependencies`:
19
19
 
20
20
  ```json
21
21
  "dependencies": {
22
- "@jimrising/easymerchantsdk-react-native": "^2.3.3"
22
+ "@jimrising/easymerchantsdk-react-native": "^2.3.4"
23
23
  }
24
24
  ```
25
25
 
@@ -39,7 +39,7 @@ repositories {
39
39
  }
40
40
 
41
41
  dependencies {
42
- implementation 'com.app:paysdk:1.6.0.15'
42
+ implementation 'com.app:paysdk:1.6.0.16'
43
43
  implementation 'com.hbb20:ccp:2.7.3'
44
44
  implementation 'com.github.bumptech.glide:glide:4.16.0'
45
45
  implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1"
@@ -291,11 +291,11 @@ public final class Request: NSObject {
291
291
  super.init()
292
292
 
293
293
  // Environment must be set by host app
294
- // if EnvironmentConfig.isEnvironmentSet == false {
295
- // self.initializationErrorMessage = "environment not set"
296
- // Request.notifyValidationError(self.initializationErrorMessage!)
297
- // return
298
- // }
294
+ if EnvironmentConfig.isEnvironmentSet == false {
295
+ self.initializationErrorMessage = "environment not set"
296
+ Request.notifyValidationError(self.initializationErrorMessage!)
297
+ return
298
+ }
299
299
 
300
300
  // ✅ Override amount if clientToken flow is used
301
301
  if let token = clientToken, !token.isEmpty {
@@ -347,34 +347,40 @@ public final class Request: NSObject {
347
347
  return
348
348
  }
349
349
 
350
- // ✅ Use recurring details from HostedCheckout API only if clientToken is present
351
- if let token = clientToken, !token.isEmpty {
352
- if let savedIsRecurring = UserStoreSingleton.shared.isRecurring,
353
- savedIsRecurring == "1" { // API returns "1" for true
354
- self.is_recurring = true
355
-
356
- if let cycles = UserStoreSingleton.shared.allowCycles,
357
- let num = Int(cycles) {
358
- self.numOfCycle = num
359
- }
360
-
361
- if let intervals = UserStoreSingleton.shared.interval {
362
- // API gives "daily,weekly,monthly" → split into array
363
- let parts = intervals.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespaces) }
364
- self.recurringIntervals = parts.compactMap { RecurringIntervals(rawValue: $0) }
365
- }
366
-
367
- if let startType = UserStoreSingleton.shared.startDateType {
368
- self.recurringStartDateType = RecurringStartDateType(rawValue: startType)
369
- }
370
-
371
- if let startDate = UserStoreSingleton.shared.startDate {
372
- self.recurringStartDate = startDate
350
+ // ✅ Handle recurring setup differently for API keys vs clientToken flow
351
+ if let token = clientToken, !token.isEmpty {
352
+ // --- Client Token Flow ---
353
+ if let savedIsRecurring = UserStoreSingleton.shared.isRecurring,
354
+ savedIsRecurring == "1" {
355
+
356
+ self.is_recurring = true
357
+ print("Recurring enabled (clientToken flow) → is_recurring = \(self.is_recurring ?? false)")
358
+
359
+ if let cycles = UserStoreSingleton.shared.allowCycles,
360
+ let num = Int(cycles) {
361
+ self.numOfCycle = num
362
+ }
363
+
364
+ if let intervals = UserStoreSingleton.shared.interval {
365
+ let parts = intervals.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespaces) }
366
+ self.recurringIntervals = parts.compactMap { RecurringIntervals(rawValue: $0) }
367
+ }
368
+
369
+ if let startType = UserStoreSingleton.shared.startDateType {
370
+ self.recurringStartDateType = RecurringStartDateType(rawValue: startType)
371
+ }
372
+
373
+ if let startDate = UserStoreSingleton.shared.startDate {
374
+ self.recurringStartDate = startDate
375
+ }
376
+ } else {
377
+ self.is_recurring = false
378
+ }
379
+ } else {
380
+ // --- API Keys Flow ---
381
+ // Keep whatever was passed from outside (don’t override)
382
+ print("Recurring setup (API keys flow) → is_recurring = \(self.is_recurring ?? false)")
373
383
  }
374
- } else {
375
- self.is_recurring = false
376
- }
377
- }
378
384
 
379
385
  // Validate recurring start date not in past
380
386
  if let startDateString = recurringStartDate,
@@ -512,6 +518,136 @@ public final class Request: NSObject {
512
518
  }
513
519
 
514
520
  //MARK: - Payment Intent Api
521
+ // func paymentIntentApi(completion: @escaping (Bool) -> Void) {
522
+ // guard let serviceURL = URL(string: EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.paymentIntent.path()) else {
523
+ // Request.notifyValidationError("Invalid payment URL.")
524
+ // print("Invalid payment URL for Payment Intent API")
525
+ // completion(false)
526
+ // return
527
+ // }
528
+ //
529
+ // var request = URLRequest(url: serviceURL)
530
+ // request.httpMethod = "POST"
531
+ // request.addValue("application/json", forHTTPHeaderField: "Content-Type")
532
+ // request.addValue(EnvironmentConfig.apiKey ?? "", forHTTPHeaderField: "X-Api-Key")
533
+ // request.addValue(EnvironmentConfig.apiSecret ?? "", forHTTPHeaderField: "X-Api-Secret")
534
+ //
535
+ // // Recurring date validation
536
+ // if let startDateString = recurringStartDate,
537
+ // let startDate = DateFormatter.recurringDateFormatter.date(from: startDateString) {
538
+ // let today = Calendar.current.startOfDay(for: Date())
539
+ // let startDay = Calendar.current.startOfDay(for: startDate)
540
+ //
541
+ // if startDay < today {
542
+ // Request.notifyValidationError("The recurring start date cannot be in the past. Please select today or a future date.")
543
+ // print("Recurring start date validation failed")
544
+ // completion(false)
545
+ // return
546
+ // }
547
+ // } else if recurringStartDate != nil {
548
+ // Request.notifyValidationError("Recurring date format should be dd/MM/yyyy")
549
+ // print("Invalid recurring date format")
550
+ // completion(false)
551
+ // return
552
+ // }
553
+ //
554
+ // let params: [String: Any] = [
555
+ // "amount": ((amount ?? 0) * 100).rounded() / 100,
556
+ // "allowed_cycles": numOfCycle ?? 0,
557
+ // "intervals": recurringIntervals?.map { $0.rawValue } ?? [],
558
+ // "is_recurring": self.is_recurring ?? false,
559
+ // "recurring_start_date": recurringStartDate ?? "",
560
+ // "recurring_start_date_type": recurringStartDateType?.rawValue ?? ""
561
+ // ]
562
+ //
563
+ // print("Payment Intent API Request Params: \(params)")
564
+ //
565
+ // do {
566
+ // request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
567
+ // } catch {
568
+ // Request.notifyValidationError("Failed to encode Payment Intent API data: \(error.localizedDescription)")
569
+ // print("Error encoding Payment Intent API data: \(error)")
570
+ // completion(false)
571
+ // return
572
+ // }
573
+ //
574
+ // let task = URLSession.shared.dataTask(with: request) { data, response, error in
575
+ // if let error = error {
576
+ // Request.notifyValidationError("Payment Intent API error: \(error.localizedDescription)")
577
+ // print("Payment Intent API error: \(error)")
578
+ // completion(false)
579
+ // return
580
+ // }
581
+ //
582
+ // guard let httpResponse = response as? HTTPURLResponse else {
583
+ // Request.notifyValidationError("Invalid response from Payment Intent API")
584
+ // print("Invalid response from Payment Intent API")
585
+ // completion(false)
586
+ // return
587
+ // }
588
+ //
589
+ // print("Payment Intent API Response Status Code: \(httpResponse.statusCode)")
590
+ //
591
+ // if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
592
+ // if let data = data {
593
+ // do {
594
+ // if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
595
+ // print("Payment Intent API Response: \(responseObject)")
596
+ // if let clientToken = responseObject["client_token"] as? String {
597
+ // UserStoreSingleton.shared.clientToken = clientToken
598
+ // print("Received clientToken: \(clientToken)")
599
+ // } else {
600
+ // Request.notifyValidationError("No client_token in Payment Intent API response")
601
+ // print("No client_token in Payment Intent API response")
602
+ // completion(false)
603
+ // return
604
+ // }
605
+ // if let paymentIntent = responseObject["payment_intent"] as? String {
606
+ // UserStoreSingleton.shared.paymentIntent = paymentIntent
607
+ // print("Received paymentIntent: \(paymentIntent)")
608
+ // }
609
+ // self.hostedCheckoutsApi { success in
610
+ // completion(success)
611
+ // }
612
+ // return
613
+ // } else {
614
+ // Request.notifyValidationError("Invalid response format from Payment Intent API")
615
+ // print("Invalid response format from Payment Intent API")
616
+ // completion(false)
617
+ // }
618
+ // } catch {
619
+ // Request.notifyValidationError("Failed to parse Payment Intent API response: \(error.localizedDescription)")
620
+ // print("Error parsing Payment Intent API response: \(error)")
621
+ // completion(false)
622
+ // }
623
+ // } else {
624
+ // Request.notifyValidationError("No response data received from Payment Intent API")
625
+ // print("No response data received from Payment Intent API")
626
+ // completion(false)
627
+ // }
628
+ // } else {
629
+ // // Default error message
630
+ // var message = "Payment Intent API failed with status code: \(httpResponse.statusCode)"
631
+ //
632
+ // if let data = data,
633
+ // let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
634
+ //
635
+ // // Prefer the "message" key from API response
636
+ // if let msg = responseObj["message"] as? String, !msg.isEmpty {
637
+ // message = "Payment Intent API error: \(msg)"
638
+ // }
639
+ // }
640
+ //
641
+ // // Send back the exact server error
642
+ // Request.notifyValidationError(message)
643
+ // print(message)
644
+ // completion(false)
645
+ // }
646
+ // }
647
+ // task.resume()
648
+ // }
649
+
650
+ // MARK: - Payment Intent Api
515
651
  func paymentIntentApi(completion: @escaping (Bool) -> Void) {
516
652
  guard let serviceURL = URL(string: EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.paymentIntent.path()) else {
517
653
  Request.notifyValidationError("Invalid payment URL.")
@@ -527,8 +663,10 @@ public final class Request: NSObject {
527
663
  request.addValue(EnvironmentConfig.apiSecret ?? "", forHTTPHeaderField: "X-Api-Secret")
528
664
 
529
665
  // Recurring date validation
666
+ var apiStartDate = ""
530
667
  if let startDateString = recurringStartDate,
531
668
  let startDate = DateFormatter.recurringDateFormatter.date(from: startDateString) {
669
+
532
670
  let today = Calendar.current.startOfDay(for: Date())
533
671
  let startDay = Calendar.current.startOfDay(for: startDate)
534
672
 
@@ -538,6 +676,12 @@ public final class Request: NSObject {
538
676
  completion(false)
539
677
  return
540
678
  }
679
+
680
+ // ✅ Convert dd/MM/yyyy -> MM/dd/yyyy for API
681
+ let apiFormatter = DateFormatter()
682
+ apiFormatter.dateFormat = "MM/dd/yyyy"
683
+ apiStartDate = apiFormatter.string(from: startDate)
684
+
541
685
  } else if recurringStartDate != nil {
542
686
  Request.notifyValidationError("Recurring date format should be dd/MM/yyyy")
543
687
  print("Invalid recurring date format")
@@ -550,7 +694,7 @@ public final class Request: NSObject {
550
694
  "allowed_cycles": numOfCycle ?? 0,
551
695
  "intervals": recurringIntervals?.map { $0.rawValue } ?? [],
552
696
  "is_recurring": self.is_recurring ?? false,
553
- "recurring_start_date": recurringStartDate ?? "",
697
+ "recurring_start_date": apiStartDate, // Correct format for API
554
698
  "recurring_start_date_type": recurringStartDateType?.rawValue ?? ""
555
699
  ]
556
700
 
@@ -587,6 +731,7 @@ public final class Request: NSObject {
587
731
  do {
588
732
  if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
589
733
  print("Payment Intent API Response: \(responseObject)")
734
+
590
735
  if let clientToken = responseObject["client_token"] as? String {
591
736
  UserStoreSingleton.shared.clientToken = clientToken
592
737
  print("Received clientToken: \(clientToken)")
@@ -596,10 +741,12 @@ public final class Request: NSObject {
596
741
  completion(false)
597
742
  return
598
743
  }
744
+
599
745
  if let paymentIntent = responseObject["payment_intent"] as? String {
600
746
  UserStoreSingleton.shared.paymentIntent = paymentIntent
601
747
  print("Received paymentIntent: \(paymentIntent)")
602
748
  }
749
+
603
750
  self.hostedCheckoutsApi { success in
604
751
  completion(success)
605
752
  }
@@ -620,14 +767,17 @@ public final class Request: NSObject {
620
767
  completion(false)
621
768
  }
622
769
  } else {
770
+ // Default error message
623
771
  var message = "Payment Intent API failed with status code: \(httpResponse.statusCode)"
772
+
624
773
  if let data = data,
625
774
  let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
626
775
  let msg = responseObj["message"] as? String, !msg.isEmpty {
627
- message = msg
776
+ message = "Payment Intent API error: \(msg)"
628
777
  }
778
+
629
779
  Request.notifyValidationError(message)
630
- print("Payment Intent API error: \(message)")
780
+ print(message)
631
781
  completion(false)
632
782
  }
633
783
  }
@@ -790,7 +940,11 @@ public final class Request: NSObject {
790
940
  if let isRecurring = recurringDetails["is_recurring"] {
791
941
  UserStoreSingleton.shared.isRecurring = "\(isRecurring)"
792
942
  print("Saved is_recurring: \(isRecurring)")
943
+ self.is_recurring = (UserStoreSingleton.shared.isRecurring == "1")
944
+ } else {
945
+ self.is_recurring = false
793
946
  }
947
+
794
948
  if let paymentIntentId = recurringDetails["payment_intent_id"] {
795
949
  UserStoreSingleton.shared.paymentIntentId = "\(paymentIntentId)"
796
950
  print("Saved payment_intent_id: \(paymentIntentId)")
@@ -803,8 +957,11 @@ public final class Request: NSObject {
803
957
  UserStoreSingleton.shared.startDateType = "\(startDateType)"
804
958
  print("Saved start_date_type: \(startDateType)")
805
959
  }
960
+ } else {
961
+ self.is_recurring = false
962
+ UserStoreSingleton.shared.isRecurring = "0"
806
963
  }
807
-
964
+
808
965
  if self.appearanceSettings == nil, let appearanceSettings = dataObject["apperance_settings"] as? [String: Any] {
809
966
  UserStoreSingleton.shared.body_bg_col = appearanceSettings["body_bg_col"] as? String
810
967
  UserStoreSingleton.shared.border_radious = appearanceSettings["border_radious"] as? String
@@ -920,6 +1077,15 @@ extension DateFormatter {
920
1077
  }()
921
1078
  }
922
1079
 
1080
+ //extension DateFormatter {
1081
+ // static let recurringDateFormatter: DateFormatter = {
1082
+ // let formatter = DateFormatter()
1083
+ // formatter.dateFormat = "MM/dd/yyyy"
1084
+ // formatter.timeZone = .current
1085
+ // return formatter
1086
+ // }()
1087
+ //}
1088
+
923
1089
 
924
1090
 
925
1091
  //extension UIApplication {
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'easymerchantsdk'
3
- s.version = '2.3.3'
3
+ s.version = '2.3.4'
4
4
  s.summary = 'A React Native SDK for Easy Merchant.'
5
5
  s.description = <<-DESC
6
6
  A React Native SDK to enable Easy Merchant functionality in mobile applications.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jimrising/easymerchantsdk-react-native",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {