@primer-io/react-native 2.6.1 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/primerioreactnative/PrimerRN.kt +1 -0
  3. package/android/src/main/java/com/primerioreactnative/PrimerRNEventListener.kt +24 -1
  4. package/android/src/main/java/com/primerioreactnative/PrimerRNHeadlessUniversalCheckoutListener.kt +24 -1
  5. package/android/src/main/java/com/primerioreactnative/datamodels/PrimerCheckoutAdditionalInfoRN.kt +13 -0
  6. package/android/src/main/java/com/primerioreactnative/datamodels/PrimerCheckoutDataRN.kt +4 -1
  7. package/android/src/main/java/com/primerioreactnative/datamodels/PrimerEvents.kt +1 -0
  8. package/android/src/main/java/com/primerioreactnative/extensions/PrimerCheckoutAdditionalInfo.kt +12 -0
  9. package/android/src/main/java/com/primerioreactnative/extensions/PrimerCheckoutData.kt +1 -1
  10. package/android/src/main/java/com/primerioreactnative/utils/PrimerHeadlessUniversalCheckoutImplementedRNCallbacks.kt +2 -0
  11. package/android/src/main/java/com/primerioreactnative/utils/PrimerImplementedRNCallbacks.kt +2 -0
  12. package/ios/DataModels/ImplementedRNCallbacks.swift +6 -3
  13. package/ios/Headless Universal Checkout/RNTPrimerHeadlessUniversalCheckout.swift +23 -1
  14. package/ios/RNTPrimer.swift +72 -49
  15. package/lib/commonjs/Primer.js +14 -3
  16. package/lib/commonjs/Primer.js.map +1 -1
  17. package/lib/commonjs/RNPrimer.js +1 -1
  18. package/lib/commonjs/RNPrimer.js.map +1 -1
  19. package/lib/commonjs/headless_checkout/PrimerHeadlessUniversalCheckout.js +17 -6
  20. package/lib/commonjs/headless_checkout/PrimerHeadlessUniversalCheckout.js.map +1 -1
  21. package/lib/commonjs/headless_checkout/RNPrimerHeadlessUniversalCheckout.js +1 -1
  22. package/lib/commonjs/headless_checkout/RNPrimerHeadlessUniversalCheckout.js.map +1 -1
  23. package/lib/commonjs/index.js +14 -0
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/models/PrimerCheckoutAdditionalInfo.js +2 -0
  26. package/lib/commonjs/models/PrimerCheckoutAdditionalInfo.js.map +1 -0
  27. package/lib/commonjs/models/PrimerCheckoutData.js +3 -0
  28. package/lib/commonjs/models/PrimerCheckoutData.js.map +1 -1
  29. package/lib/module/Primer.js +14 -3
  30. package/lib/module/Primer.js.map +1 -1
  31. package/lib/module/RNPrimer.js +1 -1
  32. package/lib/module/RNPrimer.js.map +1 -1
  33. package/lib/module/headless_checkout/PrimerHeadlessUniversalCheckout.js +17 -6
  34. package/lib/module/headless_checkout/PrimerHeadlessUniversalCheckout.js.map +1 -1
  35. package/lib/module/headless_checkout/RNPrimerHeadlessUniversalCheckout.js +1 -1
  36. package/lib/module/headless_checkout/RNPrimerHeadlessUniversalCheckout.js.map +1 -1
  37. package/lib/module/index.js +1 -0
  38. package/lib/module/index.js.map +1 -1
  39. package/lib/module/models/PrimerCheckoutAdditionalInfo.js +2 -0
  40. package/lib/module/models/PrimerCheckoutAdditionalInfo.js.map +1 -0
  41. package/lib/module/models/PrimerCheckoutData.js +2 -0
  42. package/lib/module/models/PrimerCheckoutData.js.map +1 -1
  43. package/lib/typescript/src/RNPrimer.d.ts +1 -1
  44. package/lib/typescript/src/headless_checkout/RNPrimerHeadlessUniversalCheckout.d.ts +1 -1
  45. package/lib/typescript/src/index.d.ts +1 -0
  46. package/lib/typescript/src/models/PrimerCheckoutAdditionalInfo.d.ts +10 -0
  47. package/lib/typescript/src/models/PrimerCheckoutData.d.ts +3 -1
  48. package/lib/typescript/src/models/PrimerSettings.d.ts +2 -0
  49. package/package.json +1 -1
  50. package/primer-io-react-native.podspec +1 -1
  51. package/src/Primer.ts +16 -0
  52. package/src/RNPrimer.ts +2 -0
  53. package/src/headless_checkout/PrimerHeadlessUniversalCheckout.ts +16 -0
  54. package/src/headless_checkout/RNPrimerHeadlessUniversalCheckout.ts +2 -0
  55. package/src/index.tsx +5 -1
  56. package/src/models/PrimerCheckoutAdditionalInfo.ts +11 -0
  57. package/src/models/PrimerCheckoutData.ts +5 -2
  58. package/src/models/PrimerSettings.ts +8 -6
@@ -137,5 +137,5 @@ dependencies {
137
137
  api 'com.facebook.react:react-native:+'
138
138
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
139
139
  implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
140
- implementation 'io.primer:android:2.6.0'
140
+ implementation 'io.primer:android:2.7.0'
141
141
  }
@@ -231,4 +231,5 @@ internal object Keys {
231
231
  const val ERROR = "error"
232
232
  const val RESUME_TOKEN = "resumeToken"
233
233
  const val CHECKOUT_DATA = "checkoutData"
234
+ const val ADDITIONAL_INFO = "additionalInfo"
234
235
  }
@@ -1,6 +1,7 @@
1
1
  package com.primerioreactnative
2
2
 
3
3
  import com.primerioreactnative.datamodels.*
4
+ import com.primerioreactnative.extensions.*
4
5
  import com.primerioreactnative.extensions.toPrimerCheckoutDataRN
5
6
  import com.primerioreactnative.extensions.toPrimerClientSessionRN
6
7
  import com.primerioreactnative.extensions.toPrimerPaymentMethodDataRN
@@ -13,6 +14,8 @@ import io.primer.android.completion.PrimerResumeDecisionHandler
13
14
  import io.primer.android.domain.PrimerCheckoutData
14
15
  import io.primer.android.domain.action.models.PrimerClientSession
15
16
  import io.primer.android.domain.error.models.PrimerError
17
+ import io.primer.android.domain.payments.additionalInfo.MultibancoCheckoutAdditionalInfo
18
+ import io.primer.android.domain.payments.additionalInfo.PrimerCheckoutAdditionalInfo
16
19
  import io.primer.android.domain.tokenization.models.PrimerPaymentMethodData
17
20
  import io.primer.android.domain.tokenization.models.PrimerPaymentMethodTokenData
18
21
  import kotlinx.serialization.encodeToString
@@ -38,7 +41,11 @@ class PrimerRNEventListener : PrimerCheckoutListener {
38
41
  if (implementedRNCallbacks?.isOnCheckoutCompleteImplemented == true) {
39
42
  sendEvent?.invoke(
40
43
  PrimerEvents.ON_CHECKOUT_COMPLETE.eventName,
41
- JSONObject(Json.encodeToString(checkoutData.toPrimerCheckoutDataRN()))
44
+ JSONObject(Json.encodeToString(checkoutData.toPrimerCheckoutDataRN())).apply {
45
+ val additionalInfoJson = optJSONObject(Keys.ADDITIONAL_INFO)
46
+ additionalInfoJson?.remove("type")
47
+ putOpt(Keys.ADDITIONAL_INFO, additionalInfoJson)
48
+ }
42
49
  )
43
50
  } else {
44
51
  sendError?.invoke(
@@ -139,6 +146,22 @@ class PrimerRNEventListener : PrimerCheckoutListener {
139
146
  }
140
147
  }
141
148
 
149
+ override fun onResumePending(additionalInfo: PrimerCheckoutAdditionalInfo?) {
150
+ if (implementedRNCallbacks?.isOnResumePendingImplemented == true) {
151
+ if (additionalInfo is MultibancoCheckoutAdditionalInfo) {
152
+ sendEvent?.invoke(
153
+ PrimerEvents.ON_RESUME_PENDING.eventName,
154
+ JSONObject(Json.encodeToString(additionalInfo.toCheckoutAdditionalInfoRN()))
155
+ )
156
+ }
157
+ } else {
158
+ sendError?.invoke(
159
+ ErrorTypeRN.NativeBridgeFailed
160
+ errorTo "Callback [onResumePending] should be implemented."
161
+ )
162
+ }
163
+ }
164
+
142
165
  override fun onDismissed() {
143
166
  if (implementedRNCallbacks?.isOnDismissImplemented == true) {
144
167
  sendEvent?.invoke(
@@ -4,6 +4,7 @@ import com.facebook.react.bridge.Arguments
4
4
  import com.facebook.react.bridge.Callback
5
5
  import com.facebook.react.bridge.Promise
6
6
  import com.primerioreactnative.datamodels.*
7
+ import com.primerioreactnative.extensions.*
7
8
  import com.primerioreactnative.extensions.toPrimerCheckoutDataRN
8
9
  import com.primerioreactnative.extensions.toPrimerClientSessionRN
9
10
  import com.primerioreactnative.extensions.toPrimerPaymentMethodDataRN
@@ -18,6 +19,8 @@ import io.primer.android.components.domain.core.models.PrimerHeadlessUniversalCh
18
19
  import io.primer.android.domain.PrimerCheckoutData
19
20
  import io.primer.android.domain.action.models.PrimerClientSession
20
21
  import io.primer.android.domain.error.models.PrimerError
22
+ import io.primer.android.domain.payments.additionalInfo.MultibancoCheckoutAdditionalInfo
23
+ import io.primer.android.domain.payments.additionalInfo.PrimerCheckoutAdditionalInfo
21
24
  import io.primer.android.domain.tokenization.models.PrimerPaymentMethodData
22
25
  import io.primer.android.domain.tokenization.models.PrimerPaymentMethodTokenData
23
26
  import kotlinx.serialization.encodeToString
@@ -79,7 +82,11 @@ class PrimerRNHeadlessUniversalCheckoutListener : PrimerHeadlessUniversalCheckou
79
82
  if (implementedRNCallbacks?.isOnCheckoutCompleteImplemented == true) {
80
83
  sendEvent?.invoke(
81
84
  PrimerHeadlessUniversalCheckoutEvent.ON_CHECKOUT_COMPLETE.eventName,
82
- JSONObject(Json.encodeToString(checkoutData.toPrimerCheckoutDataRN()))
85
+ JSONObject(Json.encodeToString(checkoutData.toPrimerCheckoutDataRN())).apply {
86
+ val additionalInfoJson = optJSONObject(Keys.ADDITIONAL_INFO)
87
+ additionalInfoJson?.remove("type")
88
+ putOpt(Keys.ADDITIONAL_INFO, additionalInfoJson)
89
+ }
83
90
  )
84
91
  } else {
85
92
  sendError?.invoke(
@@ -180,6 +187,22 @@ class PrimerRNHeadlessUniversalCheckoutListener : PrimerHeadlessUniversalCheckou
180
187
  }
181
188
  }
182
189
 
190
+ override fun onResumePending(additionalInfo: PrimerCheckoutAdditionalInfo?) {
191
+ if (implementedRNCallbacks?.isOnResumePendingImplemented == true) {
192
+ if (additionalInfo is MultibancoCheckoutAdditionalInfo) {
193
+ sendEvent?.invoke(
194
+ PrimerEvents.ON_RESUME_PENDING.eventName,
195
+ JSONObject(Json.encodeToString(additionalInfo.toCheckoutAdditionalInfoRN()))
196
+ )
197
+ }
198
+ } else {
199
+ sendError?.invoke(
200
+ ErrorTypeRN.NativeBridgeFailed
201
+ errorTo "Callback [onResumePending] should be implemented."
202
+ )
203
+ }
204
+ }
205
+
183
206
  override fun onFailed(
184
207
  error: PrimerError,
185
208
  checkoutData: PrimerCheckoutData?,
@@ -0,0 +1,13 @@
1
+ package com.primerioreactnative.datamodels
2
+
3
+ import kotlinx.serialization.Serializable
4
+
5
+ @Serializable
6
+ sealed class PrimerCheckoutAdditionalInfoRN
7
+
8
+ @Serializable
9
+ data class MultibancoCheckoutAdditionalInfoRN(
10
+ val expiresAt: String,
11
+ val reference: String,
12
+ val entity: String,
13
+ ) : PrimerCheckoutAdditionalInfoRN()
@@ -3,7 +3,10 @@ package com.primerioreactnative.datamodels
3
3
  import kotlinx.serialization.Serializable
4
4
 
5
5
  @Serializable
6
- data class PrimerCheckoutDataRN(val paymentRN: PrimerPaymentRN)
6
+ data class PrimerCheckoutDataRN(
7
+ val payment: PrimerPaymentRN,
8
+ val additionalInfo: PrimerCheckoutAdditionalInfoRN? = null
9
+ )
7
10
 
8
11
  @Serializable
9
12
  data class PrimerPaymentRN(
@@ -9,5 +9,6 @@ internal enum class PrimerEvents(val eventName: String) {
9
9
  ON_DISMISS("onDismiss"),
10
10
  ON_TOKENIZE_SUCCESS("onTokenizeSuccess"),
11
11
  ON_RESUME_SUCCESS("onResumeSuccess"),
12
+ ON_RESUME_PENDING("onResumePending"),
12
13
  ON_ERROR("onError"),
13
14
  }
@@ -0,0 +1,12 @@
1
+ package com.primerioreactnative.extensions
2
+
3
+ import com.primerioreactnative.datamodels.MultibancoCheckoutAdditionalInfoRN
4
+ import io.primer.android.domain.payments.additionalInfo.MultibancoCheckoutAdditionalInfo
5
+ import io.primer.android.domain.payments.additionalInfo.PrimerCheckoutAdditionalInfo
6
+
7
+ internal fun PrimerCheckoutAdditionalInfo.toCheckoutAdditionalInfoRN() = when (this) {
8
+ is MultibancoCheckoutAdditionalInfo ->
9
+ MultibancoCheckoutAdditionalInfoRN(expiresAt, reference, entity)
10
+ else -> null
11
+ }
12
+
@@ -4,4 +4,4 @@ import com.primerioreactnative.datamodels.PrimerCheckoutDataRN
4
4
  import io.primer.android.domain.PrimerCheckoutData
5
5
 
6
6
  internal fun PrimerCheckoutData.toPrimerCheckoutDataRN() =
7
- PrimerCheckoutDataRN(payment.toPrimerPaymentRN())
7
+ PrimerCheckoutDataRN(payment.toPrimerPaymentRN(), additionalInfo?.toCheckoutAdditionalInfoRN())
@@ -19,6 +19,8 @@ data class PrimerHeadlessUniversalCheckoutImplementedRNCallbacks(
19
19
  val isOnTokenizeSuccessImplemented: Boolean? = null,
20
20
  @SerialName("onResumeSuccess")
21
21
  val isOnResumeSuccessImplemented: Boolean? = null,
22
+ @SerialName("onResumePending")
23
+ val isOnResumePendingImplemented: Boolean? = null,
22
24
  @SerialName("onHUCTokenizeStart")
23
25
  val isOnHUCTokenizeStartsImplemented: Boolean? = null,
24
26
  @SerialName("onHUCPrepareStart")
@@ -21,4 +21,6 @@ data class PrimerImplementedRNCallbacks(
21
21
  val isOnTokenizeSuccessImplemented: Boolean? = null,
22
22
  @SerialName("onResumeSuccess")
23
23
  val isOnResumeSuccessImplemented: Boolean? = null,
24
+ @SerialName("onResumePending")
25
+ val isOnResumePendingImplemented: Boolean? = null,
24
26
  )
@@ -8,7 +8,7 @@
8
8
  import Foundation
9
9
 
10
10
  internal struct ImplementedRNCallbacks: Decodable {
11
-
11
+
12
12
  internal var isOnCheckoutCompleteImplemented: Bool = false
13
13
  internal var isOnBeforeClientSessionUpdateImplemented: Bool = false
14
14
  internal var isOnClientSessionUpdateImplemented: Bool = false
@@ -17,11 +17,12 @@ internal struct ImplementedRNCallbacks: Decodable {
17
17
  internal var isOnDismissImplemented: Bool = false
18
18
  internal var isOnTokenizeSuccessImplemented: Bool = false
19
19
  internal var isOnResumeSuccessImplemented: Bool = false
20
+ internal var isOnResumePendingImplemented: Bool = false
20
21
  internal var isOnHUCTokenizeStartImplemented: Bool = false
21
22
  internal var isOnHUCPrepareStartImplemented: Bool = false
22
23
  internal var isOnHUCAvailablePaymentMethodsLoadedImplemented: Bool = false
23
24
  internal var isOnHUCPaymentMethodShowImplemented: Bool = false
24
-
25
+
25
26
  enum CodingKeys: String, CodingKey {
26
27
  case isOnCheckoutCompleteImplemented = "onCheckoutComplete"
27
28
  case isOnBeforeClientSessionUpdateImplemented = "onBeforeClientSessionUpdate"
@@ -31,12 +32,13 @@ internal struct ImplementedRNCallbacks: Decodable {
31
32
  case isOnDismissImplemented = "onDismiss"
32
33
  case isOnTokenizeSuccessImplemented = "onTokenizeSuccess"
33
34
  case isOnResumeSuccessImplemented = "onResumeSuccess"
35
+ case isOnResumePendingImplemented = "onResumePending"
34
36
  case isOnHUCTokenizeStartImplemented = "onHUCTokenizeStart"
35
37
  case isOnHUCPrepareStartImplemented = "onHUCPrepareStart"
36
38
  case isOnHUCAvailablePaymentMethodsLoadedImplemented = "onHUCAvailablePaymentMethodsLoaded"
37
39
  case isOnHUCPaymentMethodShowImplemented = "onHUCPaymentMethodShow"
38
40
  }
39
-
41
+
40
42
  init(from decoder: Decoder) throws {
41
43
  let container = try decoder.container(keyedBy: CodingKeys.self)
42
44
 
@@ -48,6 +50,7 @@ internal struct ImplementedRNCallbacks: Decodable {
48
50
  self.isOnDismissImplemented = (try? container.decode(Bool?.self, forKey: .isOnDismissImplemented)) ?? false
49
51
  self.isOnTokenizeSuccessImplemented = (try? container.decode(Bool?.self, forKey: .isOnTokenizeSuccessImplemented)) ?? false
50
52
  self.isOnResumeSuccessImplemented = (try? container.decode(Bool?.self, forKey: .isOnResumeSuccessImplemented)) ?? false
53
+ self.isOnResumePendingImplemented = (try? container.decode(Bool?.self, forKey: .isOnResumePendingImplemented)) ?? false
51
54
  self.isOnHUCTokenizeStartImplemented = (try? container.decode(Bool?.self, forKey: .isOnHUCTokenizeStartImplemented)) ?? false
52
55
  self.isOnHUCPrepareStartImplemented = (try? container.decode(Bool?.self, forKey: .isOnHUCPrepareStartImplemented)) ?? false
53
56
  self.isOnHUCAvailablePaymentMethodsLoadedImplemented = (try? container.decode(Bool?.self, forKey: .isOnHUCAvailablePaymentMethodsLoadedImplemented)) ?? false
@@ -17,6 +17,7 @@ enum PrimerHeadlessUniversalCheckoutEvents: Int, CaseIterable {
17
17
  case onHUCPaymentMethodShow
18
18
  case onTokenizeSuccess
19
19
  case onResumeSuccess
20
+ case onResumePending
20
21
  case onBeforePaymentCreate
21
22
  case onBeforeClientSessionUpdate
22
23
  case onClientSessionUpdate
@@ -35,6 +36,8 @@ enum PrimerHeadlessUniversalCheckoutEvents: Int, CaseIterable {
35
36
  return "onTokenizeSuccess"
36
37
  case .onResumeSuccess:
37
38
  return "onResumeSuccess"
39
+ case .onResumePending:
40
+ return "onResumePending"
38
41
  case .onBeforePaymentCreate:
39
42
  return "onBeforePaymentCreate"
40
43
  case .onBeforeClientSessionUpdate:
@@ -398,6 +401,25 @@ extension RNTPrimerHeadlessUniversalCheckout: PrimerHeadlessUniversalCheckoutDel
398
401
  }
399
402
  }
400
403
  }
404
+
405
+ func primerHeadlessUniversalCheckoutDidEnterResumePendingWithPaymentAdditionalInfo(_ additionalInfo: PrimerCheckoutAdditionalInfo?) {
406
+ DispatchQueue.main.async {
407
+ if self.implementedRNCallbacks?.isOnResumePendingImplemented == true {
408
+ do {
409
+ let checkoutAdditionalInfo = try JSONEncoder().encode(additionalInfo)
410
+ let checkoutAdditionalInfoJson = try JSONSerialization.jsonObject(with: checkoutAdditionalInfo, options: .allowFragments)
411
+ self.sendEvent(withName: PrimerHeadlessUniversalCheckoutEvents.onResumePending.stringValue, body: checkoutAdditionalInfoJson)
412
+ } catch {
413
+ let checkoutData = PrimerCheckoutData(payment: nil, additionalInfo: additionalInfo)
414
+ self.handleRNBridgeError(error, checkoutData: checkoutData, stopOnDebug: true)
415
+ }
416
+ } else {
417
+ let err = NSError(domain: "native-bridge", code: 1, userInfo: [NSLocalizedDescriptionKey: "Callback [onResumePending] should be implemented."])
418
+ let checkoutData = PrimerCheckoutData(payment: nil, additionalInfo: additionalInfo)
419
+ self.handleRNBridgeError(err, checkoutData: checkoutData, stopOnDebug: false)
420
+ }
421
+ }
422
+ }
401
423
 
402
424
  func primerHeadlessUniversalCheckoutClientSessionWillUpdate() {
403
425
  if self.implementedRNCallbacks?.isOnBeforeClientSessionUpdateImplemented == true {
@@ -405,7 +427,7 @@ extension RNTPrimerHeadlessUniversalCheckout: PrimerHeadlessUniversalCheckoutDel
405
427
  self.sendEvent(withName: PrimerHeadlessUniversalCheckoutEvents.onBeforeClientSessionUpdate.stringValue, body: nil)
406
428
  }
407
429
  } else {
408
- // RN Dev hasn't implemented this callback, ignore.
430
+ // React Native app hasn't implemented this callback, ignore.
409
431
  }
410
432
  }
411
433
 
@@ -11,7 +11,7 @@ import UIKit
11
11
 
12
12
  @objc
13
13
  enum PrimerEvents: Int, CaseIterable {
14
-
14
+
15
15
  case onCheckoutComplete = 0
16
16
  case onBeforeClientSessionUpdate
17
17
  case onClientSessionUpdate
@@ -19,9 +19,10 @@ enum PrimerEvents: Int, CaseIterable {
19
19
  case onDismiss
20
20
  case onTokenizeSuccess
21
21
  case onResumeSuccess
22
+ case onResumePending
22
23
  case onError
23
24
  case detectImplementedRNCallbacks
24
-
25
+
25
26
  var stringValue: String {
26
27
  switch self {
27
28
  case .onCheckoutComplete:
@@ -38,6 +39,8 @@ enum PrimerEvents: Int, CaseIterable {
38
39
  return "onTokenizeSuccess"
39
40
  case .onResumeSuccess:
40
41
  return "onResumeSuccess"
42
+ case .onResumePending:
43
+ return "onResumePending"
41
44
  case .onError:
42
45
  return "onError"
43
46
  case .detectImplementedRNCallbacks:
@@ -54,28 +57,28 @@ class RNTPrimer: RCTEventEmitter {
54
57
  private var primerDidResumeWithDecisionHandler: ((_ resumeToken: String?, _ errorMessage: String?) -> Void)?
55
58
  private var primerDidFailWithErrorDecisionHandler: ((_ errorMessage: String) -> Void)?
56
59
  private var implementedRNCallbacks: ImplementedRNCallbacks?
57
-
60
+
58
61
  // MARK: - INITIALIZATION & REACT NATIVE SUPPORT
59
-
62
+
60
63
  override class func requiresMainQueueSetup() -> Bool {
61
64
  return true
62
65
  }
63
-
66
+
64
67
  deinit {
65
68
  print("🧨 deinit: \(self) \(Unmanaged.passUnretained(self).toOpaque())")
66
69
  }
67
-
70
+
68
71
  override init() {
69
72
  super.init()
70
73
  PrimerSDK.Primer.shared.delegate = self
71
74
  }
72
-
75
+
73
76
  override func supportedEvents() -> [String]! {
74
77
  return PrimerEvents.allCases.compactMap({ $0.stringValue })
75
78
  }
76
-
79
+
77
80
  // MARK: - SDK API
78
-
81
+
79
82
  @objc
80
83
  public func configure(_ settingsStr: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
81
84
  DispatchQueue.main.async {
@@ -87,7 +90,7 @@ class RNTPrimer: RCTEventEmitter {
87
90
  }
88
91
  }
89
92
  }
90
-
93
+
91
94
  @objc
92
95
  public func showUniversalCheckoutWithClientToken(_ clientToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
93
96
  DispatchQueue.main.async {
@@ -102,7 +105,7 @@ class RNTPrimer: RCTEventEmitter {
102
105
  }
103
106
  }
104
107
  }
105
-
108
+
106
109
  @objc
107
110
  public func showVaultManagerWithClientToken(_ clientToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
108
111
  DispatchQueue.main.async {
@@ -117,7 +120,7 @@ class RNTPrimer: RCTEventEmitter {
117
120
  }
118
121
  }
119
122
  }
120
-
123
+
121
124
  @objc
122
125
  public func showPaymentMethod(_ paymentMethodTypeStr: String, intent: String, clientToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
123
126
  DispatchQueue.main.async {
@@ -126,7 +129,7 @@ class RNTPrimer: RCTEventEmitter {
126
129
  let err = NSError(domain: "native-bridge", code: 0, userInfo: [NSLocalizedDescriptionKey: "Intent \(intent) is not valid."])
127
130
  throw err
128
131
  }
129
-
132
+
130
133
  PrimerSDK.Primer.shared.showPaymentMethod(paymentMethodTypeStr, withIntent: primerIntent, andClientToken: clientToken) { err in
131
134
  DispatchQueue.main.async {
132
135
  if let err = err {
@@ -141,21 +144,21 @@ class RNTPrimer: RCTEventEmitter {
141
144
  }
142
145
  }
143
146
  }
144
-
147
+
145
148
  @objc
146
149
  public func dismiss() {
147
150
  Primer.shared.dismiss()
148
151
  }
149
-
152
+
150
153
  @objc
151
154
  public func dispose() {
152
155
  Primer.shared.dismiss()
153
156
  }
154
-
157
+
155
158
  // MARK: - DECISION HANDLERS
156
-
159
+
157
160
  // MARK: Tokenization
158
-
161
+
159
162
  @objc
160
163
  public func handleTokenizationNewClientToken(_ newClientToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
161
164
  DispatchQueue.main.async {
@@ -164,7 +167,7 @@ class RNTPrimer: RCTEventEmitter {
164
167
  resolver(nil)
165
168
  }
166
169
  }
167
-
170
+
168
171
  @objc
169
172
  public func handleTokenizationSuccess(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
170
173
  DispatchQueue.main.async {
@@ -173,7 +176,7 @@ class RNTPrimer: RCTEventEmitter {
173
176
  resolver(nil)
174
177
  }
175
178
  }
176
-
179
+
177
180
  @objc
178
181
  public func handleTokenizationFailure(_ errorMessage: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
179
182
  DispatchQueue.main.async {
@@ -182,9 +185,9 @@ class RNTPrimer: RCTEventEmitter {
182
185
  resolver(nil)
183
186
  }
184
187
  }
185
-
188
+
186
189
  // MARK: Resume Payment
187
-
190
+
188
191
  @objc
189
192
  public func handleResumeWithNewClientToken(_ newClientToken: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
190
193
  DispatchQueue.main.async {
@@ -193,7 +196,7 @@ class RNTPrimer: RCTEventEmitter {
193
196
  resolver(nil)
194
197
  }
195
198
  }
196
-
199
+
197
200
  @objc
198
201
  public func handleResumeSuccess(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
199
202
  DispatchQueue.main.async {
@@ -202,7 +205,7 @@ class RNTPrimer: RCTEventEmitter {
202
205
  resolver(nil)
203
206
  }
204
207
  }
205
-
208
+
206
209
  @objc
207
210
  public func handleResumeFailure(_ errorMessage: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
208
211
  DispatchQueue.main.async {
@@ -211,9 +214,9 @@ class RNTPrimer: RCTEventEmitter {
211
214
  resolver(nil)
212
215
  }
213
216
  }
214
-
217
+
215
218
  // MARK: Payment Creation
216
-
219
+
217
220
  @objc
218
221
  public func handlePaymentCreationAbort(_ errorMessage: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
219
222
  DispatchQueue.main.async {
@@ -222,7 +225,7 @@ class RNTPrimer: RCTEventEmitter {
222
225
  resolver(nil)
223
226
  }
224
227
  }
225
-
228
+
226
229
  @objc
227
230
  public func handlePaymentCreationContinue(_ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
228
231
  DispatchQueue.main.async {
@@ -231,9 +234,9 @@ class RNTPrimer: RCTEventEmitter {
231
234
  resolver(nil)
232
235
  }
233
236
  }
234
-
237
+
235
238
  // MARK: Error Handler
236
-
239
+
237
240
  @objc
238
241
  public func showErrorMessage(_ errorMessage: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
239
242
  DispatchQueue.main.async {
@@ -242,17 +245,17 @@ class RNTPrimer: RCTEventEmitter {
242
245
  resolver(nil)
243
246
  }
244
247
  }
245
-
248
+
246
249
  // MARK: Helpers
247
-
250
+
248
251
  private func configure(settingsStr: String? = nil) throws {
249
252
  try PrimerSDK.Primer.shared.configure(settings: PrimerSettings.initialize(with: settingsStr), delegate: self)
250
253
  }
251
-
254
+
252
255
  private func detectImplemetedCallbacks() {
253
256
  sendEvent(withName: PrimerEvents.detectImplementedRNCallbacks.stringValue, body: nil)
254
257
  }
255
-
258
+
256
259
  @objc
257
260
  public func setImplementedRNCallbacks(_ implementedRNCallbacksStr: String, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
258
261
  DispatchQueue.main.async {
@@ -265,19 +268,19 @@ class RNTPrimer: RCTEventEmitter {
265
268
  resolver(nil)
266
269
  } catch {
267
270
  self.primerDidFailWithError(error, data: nil) { decisionHandler in
268
-
271
+
269
272
  }
270
273
  rejecter(error.rnError["errorId"]!, error.rnError["description"], error)
271
274
  }
272
275
  }
273
276
  }
274
-
277
+
275
278
  private func handleRNBridgeError(_ error: Error, checkoutData: PrimerCheckoutData?, stopOnDebug: Bool) {
276
279
  DispatchQueue.main.async {
277
280
  if stopOnDebug {
278
281
  assertionFailure(error.localizedDescription)
279
282
  }
280
-
283
+
281
284
  var body: [String: Any] = ["error": error.rnError]
282
285
  if let checkoutData = checkoutData,
283
286
  let data = try? JSONEncoder().encode(checkoutData),
@@ -293,7 +296,7 @@ class RNTPrimer: RCTEventEmitter {
293
296
  // MARK: - PRIMER DELEGATE
294
297
 
295
298
  extension RNTPrimer: PrimerDelegate {
296
-
299
+
297
300
  func primerDidCompleteCheckoutWithData(_ data: PrimerCheckoutData) {
298
301
  DispatchQueue.main.async {
299
302
  if self.implementedRNCallbacks?.isOnCheckoutCompleteImplemented == true {
@@ -310,7 +313,27 @@ extension RNTPrimer: PrimerDelegate {
310
313
  }
311
314
  }
312
315
  }
313
-
316
+
317
+ func primerDidEnterResumePendingWithPaymentAdditionalInfo(_ additionalInfo: PrimerCheckoutAdditionalInfo?) {
318
+ DispatchQueue.main.async {
319
+ if self.implementedRNCallbacks?.isOnResumePendingImplemented == true {
320
+ do {
321
+ let checkoutAdditionalInfo = try JSONEncoder().encode(additionalInfo)
322
+ let checkoutAdditionalInfoJson = try JSONSerialization.jsonObject(with: checkoutAdditionalInfo, options: .allowFragments)
323
+ self.sendEvent(withName: PrimerHeadlessUniversalCheckoutEvents.onResumePending.stringValue, body: checkoutAdditionalInfoJson)
324
+ } catch {
325
+ let checkoutData = PrimerCheckoutData(payment: nil, additionalInfo: additionalInfo)
326
+ self.handleRNBridgeError(error, checkoutData: checkoutData, stopOnDebug: true)
327
+ }
328
+ } else {
329
+ let err = NSError(domain: "native-bridge", code: 1, userInfo: [NSLocalizedDescriptionKey: "Callback [onResumePending] should be implemented."])
330
+ let checkoutData = PrimerCheckoutData(payment: nil, additionalInfo: additionalInfo)
331
+ self.handleRNBridgeError(err, checkoutData: checkoutData, stopOnDebug: false)
332
+ }
333
+ }
334
+ }
335
+
336
+
314
337
  func primerWillCreatePaymentWithData(_ data: PrimerCheckoutPaymentMethodData, decisionHandler: @escaping (PrimerPaymentCreationDecision) -> Void) {
315
338
  if self.implementedRNCallbacks?.isOnBeforePaymentCreateImplemented == true {
316
339
  self.primerWillCreatePaymentWithDataDecisionHandler = { errorMessage in
@@ -322,7 +345,7 @@ extension RNTPrimer: PrimerDelegate {
322
345
  }
323
346
  }
324
347
  }
325
-
348
+
326
349
  DispatchQueue.main.async {
327
350
  do {
328
351
  let checkoutPaymentmethodData = try JSONEncoder().encode(data)
@@ -339,7 +362,7 @@ extension RNTPrimer: PrimerDelegate {
339
362
  }
340
363
  }
341
364
  }
342
-
365
+
343
366
  func primerClientSessionWillUpdate() {
344
367
  if self.implementedRNCallbacks?.isOnBeforeClientSessionUpdateImplemented == true {
345
368
  DispatchQueue.main.async {
@@ -349,7 +372,7 @@ extension RNTPrimer: PrimerDelegate {
349
372
  // RN Dev hasn't implemented this callback, ignore.
350
373
  }
351
374
  }
352
-
375
+
353
376
  func primerClientSessionDidUpdate(_ clientSession: PrimerClientSession) {
354
377
  if self.implementedRNCallbacks?.isOnClientSessionUpdateImplemented == true {
355
378
  do {
@@ -365,7 +388,7 @@ extension RNTPrimer: PrimerDelegate {
365
388
  // RN Dev hasn't implemented this callback, ignore.
366
389
  }
367
390
  }
368
-
391
+
369
392
  func primerDidTokenizePaymentMethod(_ paymentMethodTokenData: PrimerPaymentMethodTokenData, decisionHandler: @escaping (PrimerResumeDecision) -> Void) {
370
393
  if self.implementedRNCallbacks?.isOnTokenizeSuccessImplemented == true {
371
394
  self.primerDidTokenizePaymentMethodDecisionHandler = { (newClientToken, errorMessage) in
@@ -379,7 +402,7 @@ extension RNTPrimer: PrimerDelegate {
379
402
  }
380
403
  }
381
404
  }
382
-
405
+
383
406
  do {
384
407
  let data = try JSONEncoder().encode(paymentMethodTokenData)
385
408
  let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
@@ -395,7 +418,7 @@ extension RNTPrimer: PrimerDelegate {
395
418
  // auto flow.
396
419
  }
397
420
  }
398
-
421
+
399
422
  func primerDidResumeWith(_ resumeToken: String, decisionHandler: @escaping (PrimerResumeDecision) -> Void) {
400
423
  if self.implementedRNCallbacks?.isOnResumeSuccessImplemented == true {
401
424
  self.primerDidResumeWithDecisionHandler = { (resumeToken, errorMessage) in
@@ -409,7 +432,7 @@ extension RNTPrimer: PrimerDelegate {
409
432
  }
410
433
  }
411
434
  }
412
-
435
+
413
436
  DispatchQueue.main.async {
414
437
  self.sendEvent(withName: PrimerEvents.onResumeSuccess.stringValue, body: ["resumeToken": resumeToken])
415
438
  }
@@ -418,7 +441,7 @@ extension RNTPrimer: PrimerDelegate {
418
441
  // Throw an error if it's the manual flow.
419
442
  }
420
443
  }
421
-
444
+
422
445
  func primerDidDismiss() {
423
446
  if self.implementedRNCallbacks?.isOnDismissImplemented == true {
424
447
  DispatchQueue.main.async {
@@ -429,7 +452,7 @@ extension RNTPrimer: PrimerDelegate {
429
452
  // Ignore!
430
453
  }
431
454
  }
432
-
455
+
433
456
  func primerDidFailWithError(_ error: Error, data: PrimerCheckoutData?, decisionHandler: @escaping ((PrimerErrorDecision) -> Void)) {
434
457
  if self.implementedRNCallbacks?.isOnErrorImplemented == true {
435
458
  // Set up the callback that will be called by **handleErrorMessage** when the RN
@@ -440,10 +463,10 @@ extension RNTPrimer: PrimerDelegate {
440
463
  decisionHandler(.fail(withErrorMessage: errorMessage.isEmpty ? nil : errorMessage))
441
464
  }
442
465
  }
443
-
466
+
444
467
  // Send the error message to the RN bridge.
445
468
  self.handleRNBridgeError(error, checkoutData: nil, stopOnDebug: false)
446
-
469
+
447
470
  } else {
448
471
  // RN dev hasn't opted in on listening SDK dismiss.
449
472
  // Ignore!