@jimrising/easymerchantsdk-react-native 1.5.1 → 1.5.3

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.
@@ -6,11 +6,13 @@
6
6
  //
7
7
 
8
8
  import UIKit
9
+ //import SDWebImage
9
10
 
10
11
  class ThreeDSecurePaymentDoneVC: BaseVC {
11
12
 
12
13
  @IBOutlet weak var imgViewPaymentDone: UIImageView!
13
14
  @IBOutlet weak var imgViewLoading: UIImageView!
15
+ // @IBOutlet weak var imgViewLoading: SDAnimatedImageView!
14
16
  @IBOutlet weak var viewMain: UIView!
15
17
  @IBOutlet weak var lblCompleteAuthentication: UILabel!
16
18
  @IBOutlet weak var btnDone: UIButton!
@@ -91,24 +93,24 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
91
93
  override func viewWillAppear(_ animated: Bool) {
92
94
  super.viewWillAppear(animated)
93
95
  uiFinishingTouchElements()
94
-
96
+
95
97
  // Restart rotating animation if missing
96
98
  if !imgViewLoading.isHidden && imgViewLoading.layer.animation(forKey: "rotationAnimation") == nil {
97
99
  startRotatingImage()
98
100
  }
99
-
101
+
100
102
  if let chargeId = (threeDSecureStatusResponse?["data"] as? [String: Any])?["charge_id"] as? String,
101
103
  !chargeId.isEmpty {
102
104
  // Charge already found - do nothing
103
105
  return
104
106
  }
105
-
107
+
106
108
  if countdownRemaining > 0 {
107
109
  imgViewLoading.isHidden = false
108
110
  imgViewPaymentDone.isHidden = true
109
- lblCompleteAuthentication.text = "Please wait while Authentication is in process..."
111
+ lblCompleteAuthentication.text = "Click the link below to complete 3DS Authentication.!"
110
112
  btnDone.isHidden = true
111
-
113
+
112
114
  if apiStatusCheckTimer == nil {
113
115
  apiStatusCheckTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { [weak self] _ in
114
116
  guard let self = self else { return }
@@ -117,23 +119,23 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
117
119
  }
118
120
  }
119
121
  }
120
-
122
+
121
123
  } else {
122
124
  imgViewLoading.layer.removeAllAnimations()
123
125
  imgViewLoading.isHidden = true
124
126
  imgViewPaymentDone.isHidden = false
125
127
  imgViewPaymentDone.image = UIImage(systemName: "exclamationmark.circle.fill")
126
128
  imgViewPaymentDone.tintColor = .systemRed
127
- lblCompleteAuthentication.text = "Please complete 3DS Authentication.!!"
129
+ lblCompleteAuthentication.text = "Click the link below to complete 3DS Authentication.!"
128
130
  btnDone.isHidden = false
129
131
  lblPaymentLink.isHidden = false
130
132
  viewPaymentDetails.isHidden = false
131
-
133
+
132
134
  apiStatusCheckTimer?.invalidate()
133
135
  apiStatusCheckTimer = nil
134
136
  }
135
137
  }
136
-
138
+
137
139
  override func viewWillDisappear(_ animated: Bool) {
138
140
  super.viewWillDisappear(animated)
139
141
  apiStatusCheckTimer?.invalidate()
@@ -142,14 +144,26 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
142
144
  oneMinuteCountdownTimer = nil
143
145
  }
144
146
 
145
- func startRotatingImage() {
146
- let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
147
- rotationAnimation.toValue = CGFloat.pi * 2 // 360 degrees in radians
148
- rotationAnimation.duration = 1 // Adjust the duration as needed
149
- rotationAnimation.isCumulative = true
150
- rotationAnimation.repeatCount = .infinity // Continuous rotation
151
- imgViewLoading.layer.add(rotationAnimation, forKey: "rotationAnimation")
152
- }
147
+ func startRotatingImage() {
148
+ let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
149
+ rotationAnimation.toValue = CGFloat.pi * 2 // 360 degrees in radians
150
+ rotationAnimation.duration = 1 // Adjust the duration as needed
151
+ rotationAnimation.isCumulative = true
152
+ rotationAnimation.repeatCount = .infinity // Continuous rotation
153
+ imgViewLoading.layer.add(rotationAnimation, forKey: "rotationAnimation")
154
+ }
155
+
156
+ // private func showHourglassGIF() {
157
+ // if let bundlePath = Bundle.easyPayBundle.path(forResource: "hourglass", ofType: "gif") {
158
+ // let url = URL(fileURLWithPath: bundlePath)
159
+ // imgViewLoading.sd_setImage(with: url)
160
+ // self.imgViewLoading.contentMode = .redraw
161
+ // }
162
+ // }
163
+
164
+ // func startRotatingImage() {
165
+ // showHourglassGIF()
166
+ // }
153
167
 
154
168
  private func setupTapOnLabel() {
155
169
  if let url = redirectURL {
@@ -170,64 +184,64 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
170
184
  }
171
185
  UIApplication.shared.open(url, options: [:], completionHandler: nil)
172
186
  }
173
-
187
+
174
188
  private func startOneMinuteCountdownAndAPICheck() {
175
189
  startRotatingImage()
176
190
  imgViewPaymentDone.isHidden = true
177
191
  imgViewLoading.isHidden = false
178
- lblCompleteAuthentication.text = "Please wait while Authentication is in process..."
192
+ lblCompleteAuthentication.text = "Click the link below to complete 3DS Authentication.!"
179
193
  btnDone.isHidden = true
180
-
194
+
181
195
  apiStatusCheckTimer?.invalidate()
182
196
  apiStatusCheckTimer = nil
183
-
197
+
184
198
  initialAPIGroup.enter()
185
199
  checkThreeDSecureStatus { [weak self] in
186
200
  self?.initialAPIGroup.leave()
187
201
  }
188
-
202
+
189
203
  countdownRemaining = 60
190
-
204
+
191
205
  oneMinuteCountdownTimer = DispatchSource.makeTimerSource(queue: .main)
192
206
  oneMinuteCountdownTimer?.schedule(deadline: .now(), repeating: .seconds(1))
193
207
  oneMinuteCountdownTimer?.setEventHandler { [weak self] in
194
208
  guard let self = self else { return }
195
-
209
+
196
210
  self.countdownRemaining -= 1
197
211
  if self.countdownRemaining <= 0 {
198
212
  self.oneMinuteCountdownTimer?.cancel()
199
213
  self.oneMinuteCountdownTimer = nil
200
-
214
+
201
215
  DispatchQueue.main.async {
202
216
  self.imgViewLoading.layer.removeAllAnimations()
203
217
  self.imgViewLoading.isHidden = true
204
218
  self.imgViewPaymentDone.isHidden = false
205
- self.lblCompleteAuthentication.text = "Please complete 3DS Authentication.!!"
219
+ self.lblCompleteAuthentication.text = "Click the link below to complete 3DS Authentication.!"
206
220
  self.btnDone.isHidden = false
207
221
  self.lblPaymentLink.isHidden = false
208
222
  self.viewPaymentDetails.isHidden = false
209
-
223
+
210
224
  if let json = self.threeDSecureStatusResponse,
211
225
  let data = json["data"] as? [String: Any],
212
226
  let chargeId = data["charge_id"],
213
227
  chargeId is NSNull || (chargeId as? String ?? "").isEmpty {
214
228
  self.imgViewPaymentDone.image = UIImage(systemName: "exclamationmark.circle.fill")
215
229
  self.imgViewPaymentDone.tintColor = .systemRed
216
-
230
+
217
231
  let refToken = data["ref_token"] as? String ?? "N/A"
218
232
  let chargeId = data["charge_id"] as? String ?? "N/A"
219
233
  let transactionId = data["transaction_id"] as? String ?? "N/A"
220
234
  let subscriptionId = data["subscription_id"] as? String ?? "N/A"
221
235
  let createdAt = data["created_at"] as? String ?? ""
222
236
  let status = data["status"] as? String ?? ""
223
-
237
+
224
238
  let formattedDate: String
225
239
  if let date = self.convertToDate(dateString: createdAt) {
226
240
  formattedDate = self.formatDate(date: date)
227
241
  } else {
228
242
  formattedDate = "N/A"
229
243
  }
230
-
244
+
231
245
  self.lblChargeId.text = "\(chargeId)"
232
246
  self.lblTransactionId.text = "\(transactionId)"
233
247
  self.lblSubscriptionId.text = "\(subscriptionId)"
@@ -240,43 +254,43 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
240
254
  }
241
255
  }
242
256
  oneMinuteCountdownTimer?.resume()
243
-
257
+
244
258
  // ✅ API check timer: runs continuously every 5 seconds until success/failure
245
259
  apiStatusCheckTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
246
260
  guard let self = self else { return }
247
261
  self.checkThreeDSecureStatus(completion: nil)
248
262
  }
249
263
  }
250
-
264
+
251
265
  @IBAction func actionBtnDone(_ sender: UIButton) {
252
266
  var resultBillingInfo: [String: Any]? = nil
253
267
  var resultAdditionalInfo: [String: Any]? = nil
254
-
268
+
255
269
  // Only assign billingInfo if it contains at least one non-empty key-value pair
256
270
  if let billing = billingInfo, !billing.isEmpty {
257
271
  resultBillingInfo = billing
258
272
  }
259
-
273
+
260
274
  // Combine 3DS status into additionalInfo if needed
261
275
  var combinedAdditionalInfo = additionalInfo ?? [:]
262
276
  if let threeDS = threeDSecureStatusResponse {
263
277
  combinedAdditionalInfo["threeDSecureStatus"] = threeDS
264
278
  }
265
-
279
+
266
280
  // Only assign additionalInfo if it contains at least one non-empty key-value pair
267
281
  if !combinedAdditionalInfo.isEmpty {
268
282
  resultAdditionalInfo = combinedAdditionalInfo
269
283
  }
270
-
271
- let result = Result(
284
+
285
+ let result = SDKResult(
272
286
  type: .success,
273
287
  chargeData: chargeData,
274
288
  billingInfo: resultBillingInfo,
275
289
  additionalInfo: resultAdditionalInfo
276
290
  )
277
-
291
+
278
292
  easyPayDelegate?.easyPayController(self.navigationController as! EasyPayViewController, didFinishWith: result)
279
-
293
+
280
294
  if let easyPayVC = self.navigationController as? EasyPayViewController {
281
295
  easyPayVC.dismiss(animated: true, completion: {
282
296
  if let delegate = easyPayVC.easyPayDelegate {
@@ -286,14 +300,15 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
286
300
  })
287
301
  }
288
302
  }
289
-
303
+
290
304
  func uiFinishingTouchElements() {
291
305
  // Set background color for the main view
292
306
  if let containerBGcolor = UserStoreSingleton.shared.container_bg_col,
293
307
  let uiColor = UIColor(hex: containerBGcolor) {
294
308
  self.view.backgroundColor = uiColor
295
309
  self.viewMain.backgroundColor = uiColor
296
- // self.viewOverlay.backgroundColor = uiColor.withAlphaComponent(0.3)
310
+ self.imgViewLoading.backgroundColor = uiColor
311
+ // self.viewOverlay.backgroundColor = uiColor.withAlphaComponent(0.3)
297
312
  }
298
313
 
299
314
  if let primaryBtnBackGroundColor = UserStoreSingleton.shared.primary_btn_bg_col,
@@ -358,7 +373,7 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
358
373
  formatter.timeZone = TimeZone(abbreviation: "UTC")
359
374
  return formatter.date(from: dateString)
360
375
  }
361
-
376
+
362
377
  private func formatDate(date: Date) -> String {
363
378
  let formatter = DateFormatter()
364
379
  formatter.dateFormat = "dd/MM/yyyy, HH:mm:ss"
@@ -373,50 +388,50 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
373
388
  completion?()
374
389
  return
375
390
  }
376
-
391
+
377
392
  let urlString = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.threeDSecureStatus(secureToken).path()
378
393
  print("Final 3DS status URL: \(urlString)")
379
-
394
+
380
395
  guard let url = URL(string: urlString) else {
381
396
  print("Invalid URL")
382
397
  completion?()
383
398
  return
384
399
  }
385
-
400
+
386
401
  var uRLRequest = URLRequest(url: url)
387
402
  uRLRequest.httpMethod = "GET"
388
403
  uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
389
-
404
+
390
405
  if let token = UserStoreSingleton.shared.customerToken {
391
406
  uRLRequest.addValue(token, forHTTPHeaderField: "Customer-Token")
392
407
  }
393
-
408
+
394
409
  if let apiKey = EnvironmentConfig.apiKey,
395
410
  let apiSecret = EnvironmentConfig.apiSecret {
396
411
  uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
397
412
  uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
398
413
  }
399
-
414
+
400
415
  let task = URLSession.shared.dataTask(with: uRLRequest) { [weak self] data, response, error in
401
416
  defer { completion?() }
402
-
417
+
403
418
  guard let self = self else { return }
404
-
419
+
405
420
  if let error = error {
406
421
  print("3DS status check error:", error.localizedDescription)
407
422
  return
408
423
  }
409
-
424
+
410
425
  guard let data = data else {
411
426
  print("No data in response")
412
427
  return
413
428
  }
414
-
429
+
415
430
  do {
416
431
  if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
417
432
  print("3DS status response:", json)
418
433
  self.threeDSecureStatusResponse = json
419
-
434
+
420
435
  if let dataDict = json["data"] as? [String: Any] {
421
436
  DispatchQueue.main.async {
422
437
  let chargeId = dataDict["charge_id"] as? String ?? "N/A"
@@ -425,14 +440,14 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
425
440
  let createdAt = dataDict["created_at"] as? String ?? ""
426
441
  let referenceId = dataDict["ref_token"] as? String ?? "N/A"
427
442
  let status = dataDict["status"] as? String ?? "N/A"
428
-
443
+
429
444
  let formattedDate: String
430
445
  if let date = self.convertToDate(dateString: createdAt) {
431
446
  formattedDate = self.formatDate(date: date)
432
447
  } else {
433
448
  formattedDate = "N/A"
434
449
  }
435
-
450
+
436
451
  self.lblChargeId.text = chargeId
437
452
  self.lblTransactionId.text = transactionId
438
453
  self.lblSubscriptionId.text = subscriptionId
@@ -440,16 +455,15 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
440
455
  self.lblTotal.text = "$\(self.amount ?? 0)"
441
456
  self.lblRefferenceId.text = referenceId
442
457
  self.lblStatus.text = status
443
-
458
+
444
459
  if status.lowercased() == "failed" {
445
- // Handle failed status
446
- self.imgViewPaymentDone.image = UIImage(systemName: "xmark.circle.fill")
460
+ self.imgViewPaymentDone.image = UIImage(named: "payment_error_icon", in: .easyPayBundle, compatibleWith: nil)
447
461
  self.imgViewPaymentDone.tintColor = .systemRed
448
462
  self.apiStatusCheckTimer?.invalidate()
449
463
  self.apiStatusCheckTimer = nil
450
464
  self.oneMinuteCountdownTimer?.cancel()
451
465
  self.oneMinuteCountdownTimer = nil
452
-
466
+
453
467
  self.imgViewLoading.layer.removeAllAnimations()
454
468
  self.imgViewLoading.isHidden = true
455
469
  self.imgViewPaymentDone.isHidden = false
@@ -457,15 +471,16 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
457
471
  self.btnDone.isHidden = false
458
472
  self.lblPaymentLink.isHidden = false
459
473
  self.viewPaymentDetails.isHidden = false
460
-
461
- } else if status.lowercased() == "completed" {
474
+
475
+ }
476
+ else if status.lowercased() == "completed" {
462
477
  // Success case
463
478
  self.imgViewPaymentDone.image = UIImage(named: "payment_done_icon", in: .easyPayBundle, compatibleWith: nil)
464
479
  self.apiStatusCheckTimer?.invalidate()
465
480
  self.apiStatusCheckTimer = nil
466
481
  self.oneMinuteCountdownTimer?.cancel()
467
482
  self.oneMinuteCountdownTimer = nil
468
-
483
+
469
484
  self.imgViewLoading.layer.removeAllAnimations()
470
485
  self.imgViewLoading.isHidden = true
471
486
  self.imgViewPaymentDone.isHidden = false
@@ -473,7 +488,6 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
473
488
  self.btnDone.isHidden = false
474
489
  self.lblPaymentLink.isHidden = false
475
490
  self.viewPaymentDetails.isHidden = false
476
-
477
491
  } else {
478
492
  // Still waiting
479
493
  self.imgViewPaymentDone.image = UIImage(systemName: "exclamationmark.circle.fill")
@@ -488,6 +502,6 @@ class ThreeDSecurePaymentDoneVC: BaseVC {
488
502
  }
489
503
  task.resume()
490
504
  }
491
-
505
+
492
506
  }
493
507
 
Binary file
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = 'easymerchantsdk'
3
- s.version = '1.5.1'
3
+ s.version = '1.5.3'
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.
@@ -27,6 +27,7 @@ Pod::Spec.new do |s|
27
27
  s.source_files = [
28
28
  "Bundle/*",
29
29
  "Classes/*",
30
+ "ApiManager/*",
30
31
  "CustomComponents/**/*",
31
32
  "Extensions/**/*",
32
33
  "Models/**/*",
@@ -44,6 +45,7 @@ Pod::Spec.new do |s|
44
45
  "easymerchantsdk" => [
45
46
  "Bundle/*",
46
47
  "Classes/*",
48
+ "ApiManager/*",
47
49
  "CustomComponents/**/*",
48
50
  "Extensions/**/*",
49
51
  "Models/*",