@primer-io/react-native 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/primerioreactnative/PrimerCardNumberEditTextManager.kt +83 -0
- package/android/src/main/java/com/primerioreactnative/PrimerRN.kt +2 -2
- package/android/src/main/java/com/primerioreactnative/PrimerRNHeadlessUniversalCheckout.kt +244 -0
- package/android/src/main/java/com/primerioreactnative/PrimerRNHeadlessUniversalCheckoutListener.kt +275 -0
- package/android/src/main/java/com/primerioreactnative/ReactNativePackage.kt +14 -3
- package/android/src/main/java/com/primerioreactnative/datamodels/PrimerErrorRN.kt +3 -0
- package/android/src/main/java/com/primerioreactnative/huc/assets/AssetsManager.kt +56 -0
- package/android/src/main/java/com/primerioreactnative/huc/events/PrimerHeadlessUniversalCheckoutEvent.kt +15 -0
- package/android/src/main/java/com/primerioreactnative/utils/PrimerHeadlessUniversalCheckoutImplementedRNCallbacks.kt +31 -0
- package/ios/Core/ReactNative-Bridging-Header.h +14 -0
- package/ios/DataModels/ImplementedRNCallbacks.swift +34 -9
- package/ios/DataModels/PrimerSettingsRN.swift +15 -16
- package/ios/Headless Universal Checkout/RNTPrimerCardNumberInputElementManager.m +23 -0
- package/ios/Headless Universal Checkout/RNTPrimerHeadlessUniversalCheckout.m +62 -0
- package/ios/Headless Universal Checkout/RNTPrimerHeadlessUniversalCheckout.swift +493 -0
- package/ios/Headless Universal Checkout/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.m +14 -0
- package/ios/Headless Universal Checkout/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.swift +117 -0
- package/ios/RNTPrimer.m +2 -0
- package/ios/RNTPrimer.swift +56 -51
- package/ios/ReactNative-Bridging-Header.h +1 -0
- package/lib/commonjs/Primer.js +6 -0
- package/lib/commonjs/Primer.js.map +1 -1
- package/lib/commonjs/PrimerInput.js +80 -0
- package/lib/commonjs/PrimerInput.js.map +1 -0
- package/lib/commonjs/RNPrimer.js +11 -0
- package/lib/commonjs/RNPrimer.js.map +1 -1
- package/lib/commonjs/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.js +14 -0
- package/lib/commonjs/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.js.map +1 -0
- package/lib/commonjs/headless_checkout/PrimerHeadlessUniversalCheckout.js +286 -0
- package/lib/commonjs/headless_checkout/PrimerHeadlessUniversalCheckout.js.map +1 -0
- package/lib/commonjs/headless_checkout/RNPrimerHeadlessUniversalCheckout.js +197 -0
- package/lib/commonjs/headless_checkout/RNPrimerHeadlessUniversalCheckout.js.map +1 -0
- package/lib/commonjs/{models/Primer.js → headless_checkout/types.js} +1 -1
- package/lib/commonjs/{models/Primer.js.map → headless_checkout/types.js.map} +0 -0
- package/lib/commonjs/index.js +13 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/PrimerInterfaces.js +6 -0
- package/lib/{module/models/Primer.js.map → commonjs/models/PrimerInterfaces.js.map} +0 -0
- package/lib/module/Primer.js +7 -2
- package/lib/module/Primer.js.map +1 -1
- package/lib/module/PrimerInput.js +46 -0
- package/lib/module/PrimerInput.js.map +1 -0
- package/lib/module/RNPrimer.js +11 -0
- package/lib/module/RNPrimer.js.map +1 -1
- package/lib/module/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.js +5 -0
- package/lib/module/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.js.map +1 -0
- package/lib/module/headless_checkout/PrimerHeadlessUniversalCheckout.js +273 -0
- package/lib/module/headless_checkout/PrimerHeadlessUniversalCheckout.js.map +1 -0
- package/lib/module/headless_checkout/RNPrimerHeadlessUniversalCheckout.js +188 -0
- package/lib/module/headless_checkout/RNPrimerHeadlessUniversalCheckout.js.map +1 -0
- package/lib/module/headless_checkout/types.js +2 -0
- package/lib/module/headless_checkout/types.js.map +1 -0
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/PrimerInterfaces.js +2 -0
- package/lib/module/models/PrimerInterfaces.js.map +1 -0
- package/lib/typescript/MerchantExample/App.d.ts +11 -0
- package/lib/typescript/src/Primer.d.ts +2 -0
- package/lib/typescript/src/PrimerInput.d.ts +15 -0
- package/lib/typescript/{RNPrimer.d.ts → src/RNPrimer.d.ts} +1 -0
- package/lib/typescript/src/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.d.ts +1 -0
- package/lib/typescript/src/headless_checkout/PrimerHeadlessUniversalCheckout.d.ts +11 -0
- package/lib/typescript/src/headless_checkout/RNPrimerHeadlessUniversalCheckout.d.ts +22 -0
- package/lib/typescript/src/headless_checkout/types.d.ts +22 -0
- package/lib/typescript/{index.d.ts → src/index.d.ts} +2 -1
- package/lib/typescript/{models → src/models}/PrimerCheckoutData.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerCheckoutPaymentMethodData.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerClientSession.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerCountryCode.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerCurrencyCode.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerError.d.ts +0 -0
- package/lib/typescript/{models/Primer.d.ts → src/models/PrimerInterfaces.d.ts} +2 -1
- package/lib/typescript/{models → src/models}/PrimerPaymentMethodTokenData.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerSessionIntent.d.ts +0 -0
- package/lib/typescript/{models → src/models}/PrimerSettings.d.ts +6 -2
- package/lib/typescript/{models → src/models}/PrimerTheme.d.ts +0 -0
- package/lib/typescript/{utils → src/utils}/index.d.ts +0 -0
- package/package.json +1 -1
- package/primer-io-react-native.podspec +1 -1
- package/src/Primer.ts +6 -1
- package/src/PrimerInput.tsx +73 -0
- package/src/RNPrimer.ts +13 -0
- package/src/RNTPrimerHeadlessUniversalCheckoutCardFormUIManager.tsx +2 -0
- package/src/headless_checkout/PrimerHeadlessUniversalCheckout.ts +327 -0
- package/src/headless_checkout/RNPrimerHeadlessUniversalCheckout.ts +252 -0
- package/src/headless_checkout/types.ts +32 -0
- package/src/index.tsx +4 -2
- package/src/models/{Primer.ts → PrimerInterfaces.ts} +2 -1
- package/src/models/PrimerSettings.ts +17 -2
- package/lib/module/models/Primer.js +0 -2
- package/lib/typescript/Primer.d.ts +0 -2
package/android/build.gradle
CHANGED
|
@@ -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.0
|
|
140
|
+
implementation 'io.primer:android:2.1.0'
|
|
141
141
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package com.primerioreactnative
|
|
2
|
+
|
|
3
|
+
import android.content.res.ColorStateList
|
|
4
|
+
import android.graphics.Color
|
|
5
|
+
import android.graphics.drawable.ColorDrawable
|
|
6
|
+
import android.graphics.drawable.GradientDrawable
|
|
7
|
+
import android.view.ViewGroup
|
|
8
|
+
import android.widget.EditText
|
|
9
|
+
import android.widget.LinearLayout
|
|
10
|
+
import android.widget.TextView
|
|
11
|
+
import com.facebook.drawee.backends.pipeline.Fresco
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
14
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
15
|
+
import com.facebook.react.uimanager.ViewProps
|
|
16
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
17
|
+
import com.facebook.react.views.image.ReactImageView
|
|
18
|
+
import io.primer.android.components.manager.PrimerCardManager
|
|
19
|
+
import io.primer.android.components.manager.PrimerUniversalCheckoutCardManagerInterface
|
|
20
|
+
import io.primer.android.components.ui.widgets.*
|
|
21
|
+
|
|
22
|
+
val listOfTextInputs = mutableListOf<PrimerEditText>()
|
|
23
|
+
|
|
24
|
+
class PrimerCardNumberEditTextManager : SimpleViewManager<PrimerCardNumberEditText>() {
|
|
25
|
+
|
|
26
|
+
override fun getName(): String {
|
|
27
|
+
return REACT_CLASS
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override fun createViewInstance(reactContext: ThemedReactContext): PrimerCardNumberEditText {
|
|
31
|
+
val editText = PrimerCardNumberEditText(reactContext)
|
|
32
|
+
return editText
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
companion object {
|
|
36
|
+
const val REACT_CLASS = "PrimerCardNumberEditText"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class PrimerCardholderNameEditTextManager : SimpleViewManager<PrimerCardholderNameEditText>() {
|
|
41
|
+
|
|
42
|
+
override fun getName(): String {
|
|
43
|
+
return REACT_CLASS
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun createViewInstance(reactContext: ThemedReactContext): PrimerCardholderNameEditText {
|
|
47
|
+
return PrimerCardholderNameEditText(reactContext)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
companion object {
|
|
51
|
+
const val REACT_CLASS = "PrimerCardholderNameEditText"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class PrimerExpiryEditTextManager : SimpleViewManager<PrimerExpiryEditText>() {
|
|
56
|
+
|
|
57
|
+
override fun getName(): String {
|
|
58
|
+
return REACT_CLASS
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override fun createViewInstance(reactContext: ThemedReactContext): PrimerExpiryEditText {
|
|
62
|
+
return PrimerExpiryEditText(reactContext)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
companion object {
|
|
66
|
+
const val REACT_CLASS = "PrimerExpiryEditText"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class PrimerCvvEditTextManager : SimpleViewManager<PrimerCvvEditText>() {
|
|
71
|
+
|
|
72
|
+
override fun getName(): String {
|
|
73
|
+
return REACT_CLASS
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
override fun createViewInstance(reactContext: ThemedReactContext): PrimerCvvEditText {
|
|
77
|
+
return PrimerCvvEditText(reactContext)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
companion object {
|
|
81
|
+
const val REACT_CLASS = "PrimerCvvEditText"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -16,9 +16,9 @@ import kotlinx.serialization.encodeToString
|
|
|
16
16
|
import kotlinx.serialization.json.Json
|
|
17
17
|
import org.json.JSONObject
|
|
18
18
|
|
|
19
|
-
class PrimerRN(reactContext: ReactApplicationContext
|
|
19
|
+
class PrimerRN(private val reactContext: ReactApplicationContext, private val json: Json) :
|
|
20
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
20
21
|
private var mListener = PrimerRNEventListener()
|
|
21
|
-
private val json = Json { ignoreUnknownKeys = true }
|
|
22
22
|
|
|
23
23
|
init {
|
|
24
24
|
mListener.sendEvent = { eventName, paramsJson -> sendEvent(eventName, paramsJson) }
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
package com.primerioreactnative
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import androidx.core.content.ContextCompat
|
|
5
|
+
import com.facebook.react.bridge.*
|
|
6
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
7
|
+
import com.primerioreactnative.datamodels.*
|
|
8
|
+
import com.primerioreactnative.huc.assets.AssetsManager
|
|
9
|
+
import com.primerioreactnative.huc.assets.AssetsManager.drawableToBitmap
|
|
10
|
+
import com.primerioreactnative.huc.assets.AssetsManager.getFile
|
|
11
|
+
import com.primerioreactnative.huc.events.PrimerHeadlessUniversalCheckoutEvent
|
|
12
|
+
import com.primerioreactnative.utils.PrimerHeadlessUniversalCheckoutImplementedRNCallbacks
|
|
13
|
+
import com.primerioreactnative.utils.convertJsonToMap
|
|
14
|
+
import com.primerioreactnative.utils.errorTo
|
|
15
|
+
import io.primer.android.ExperimentalPrimerApi
|
|
16
|
+
import io.primer.android.components.PrimerHeadlessUniversalCheckout
|
|
17
|
+
import io.primer.android.components.ui.assets.ImageType
|
|
18
|
+
import io.primer.android.data.configuration.models.PaymentMethodType
|
|
19
|
+
import io.primer.android.data.configuration.models.PrimerPaymentMethodType
|
|
20
|
+
import kotlinx.serialization.decodeFromString
|
|
21
|
+
import kotlinx.serialization.encodeToString
|
|
22
|
+
import kotlinx.serialization.json.Json
|
|
23
|
+
import org.json.JSONObject
|
|
24
|
+
|
|
25
|
+
@ExperimentalPrimerApi
|
|
26
|
+
class PrimerRNHeadlessUniversalCheckout(
|
|
27
|
+
private val reactContext: ReactApplicationContext,
|
|
28
|
+
private val json: Json,
|
|
29
|
+
) : ReactContextBaseJavaModule(reactContext) {
|
|
30
|
+
|
|
31
|
+
private val listener = PrimerRNHeadlessUniversalCheckoutListener()
|
|
32
|
+
|
|
33
|
+
init {
|
|
34
|
+
listener.sendEvent = { eventName, paramsJson -> sendEvent(eventName, paramsJson) }
|
|
35
|
+
listener.sendError = { paramsJson -> onError(paramsJson) }
|
|
36
|
+
listener.sendErrorWithCheckoutData =
|
|
37
|
+
{ paramsJson, checkoutData -> onError(paramsJson, checkoutData) }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override fun getName(): String {
|
|
41
|
+
return "PrimerHeadlessUniversalCheckout"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@ReactMethod
|
|
45
|
+
fun startWithClientToken(
|
|
46
|
+
clientToken: String,
|
|
47
|
+
settingsStr: String?,
|
|
48
|
+
errorCallback: Callback,
|
|
49
|
+
successCallback: Callback
|
|
50
|
+
) {
|
|
51
|
+
listener.successCallback = successCallback
|
|
52
|
+
try {
|
|
53
|
+
val settings =
|
|
54
|
+
if (settingsStr.isNullOrBlank()) PrimerSettingsRN() else json.decodeFromString(
|
|
55
|
+
settingsStr
|
|
56
|
+
)
|
|
57
|
+
PrimerHeadlessUniversalCheckout.current.start(
|
|
58
|
+
reactContext,
|
|
59
|
+
clientToken,
|
|
60
|
+
settings.toPrimerSettings(),
|
|
61
|
+
listener
|
|
62
|
+
)
|
|
63
|
+
} catch (e: Exception) {
|
|
64
|
+
errorCallback.invoke(
|
|
65
|
+
json.encodeToString(
|
|
66
|
+
ErrorTypeRN.NativeBridgeFailed errorTo
|
|
67
|
+
"failed to initialise PrimerHeadlessUniversalCheckout SDK, error: $e",
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@ReactMethod
|
|
74
|
+
fun showPaymentMethod(paymentMethodTypeStr: String, promise: Promise) {
|
|
75
|
+
val primerPaymentMethodType = PrimerPaymentMethodType.safeValueOf(paymentMethodTypeStr)
|
|
76
|
+
if (primerPaymentMethodType == PaymentMethodType.UNKNOWN) {
|
|
77
|
+
val exception =
|
|
78
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "Payment method type $paymentMethodTypeStr is not valid."
|
|
79
|
+
onError(exception)
|
|
80
|
+
promise.reject(exception.errorId, exception.description)
|
|
81
|
+
} else {
|
|
82
|
+
PrimerHeadlessUniversalCheckout.current.showPaymentMethod(
|
|
83
|
+
reactContext,
|
|
84
|
+
primerPaymentMethodType
|
|
85
|
+
)
|
|
86
|
+
promise.resolve(null)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@ReactMethod
|
|
91
|
+
fun disposePrimerHeadlessUniversalCheckout() {
|
|
92
|
+
PrimerHeadlessUniversalCheckout.current.cleanup()
|
|
93
|
+
listener.removeCallbacksAndHandlers()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@ReactMethod
|
|
97
|
+
fun getAssetForPaymentMethodType(
|
|
98
|
+
paymentMethodType: String,
|
|
99
|
+
assetType: String,
|
|
100
|
+
errorCallback: Callback,
|
|
101
|
+
successCallback: Callback
|
|
102
|
+
) {
|
|
103
|
+
|
|
104
|
+
val primerPaymentMethodType = PrimerPaymentMethodType.safeValueOf(paymentMethodType)
|
|
105
|
+
val type = ImageType.values().find { it.name.equals(assetType, ignoreCase = true) }
|
|
106
|
+
when {
|
|
107
|
+
primerPaymentMethodType == PaymentMethodType.UNKNOWN -> {
|
|
108
|
+
errorCallback.invoke(
|
|
109
|
+
json.encodeToString(
|
|
110
|
+
ErrorTypeRN.InvalidPaymentMethodType errorTo
|
|
111
|
+
"Asset for $paymentMethodType does not exist, make sure you don't have any typos."
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
type == null -> {
|
|
116
|
+
errorCallback.invoke(
|
|
117
|
+
json.encodeToString(
|
|
118
|
+
ErrorTypeRN.AssetMismatch errorTo
|
|
119
|
+
"You have provided assetType=$assetType, but variable assetType can be 'LOGO' or 'ICON'."
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
else -> {
|
|
124
|
+
PrimerHeadlessUniversalCheckout.getAsset(primerPaymentMethodType, type)?.let { resourceId ->
|
|
125
|
+
val file = getFile(reactContext, paymentMethodType)
|
|
126
|
+
AssetsManager.saveBitmapToFile(
|
|
127
|
+
file,
|
|
128
|
+
drawableToBitmap(ContextCompat.getDrawable(reactContext, resourceId)!!),
|
|
129
|
+
)
|
|
130
|
+
successCallback.invoke("file://${file.absolutePath}")
|
|
131
|
+
} ?: run {
|
|
132
|
+
errorCallback.invoke(
|
|
133
|
+
json.encodeToString(
|
|
134
|
+
ErrorTypeRN.AssetMissing errorTo
|
|
135
|
+
"Failed to find $assetType for $paymentMethodType"
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// region tokenization handlers
|
|
144
|
+
@ReactMethod
|
|
145
|
+
fun handleTokenizationNewClientToken(newClientToken: String, promise: Promise) {
|
|
146
|
+
listener.handleTokenizationNewClientToken(newClientToken)
|
|
147
|
+
promise.resolve(null)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@ReactMethod
|
|
151
|
+
fun handleTokenizationSuccess(promise: Promise) {
|
|
152
|
+
listener.handleTokenizationSuccess(promise)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@ReactMethod
|
|
156
|
+
fun handleTokenizationFailure(errorMessage: String?, promise: Promise) {
|
|
157
|
+
listener.handleTokenizationFailure(errorMessage.orEmpty(), promise)
|
|
158
|
+
}
|
|
159
|
+
// endregion
|
|
160
|
+
|
|
161
|
+
// region resume handlers
|
|
162
|
+
@ReactMethod
|
|
163
|
+
fun handleResumeNewClientToken(newClientToken: String, promise: Promise) {
|
|
164
|
+
listener.handleResumeNewClientToken(newClientToken)
|
|
165
|
+
promise.resolve(null)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@ReactMethod
|
|
169
|
+
fun handleResumeSuccess(promise: Promise) {
|
|
170
|
+
listener.handleResumeSuccess(promise)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@ReactMethod
|
|
174
|
+
fun handleResumeFailure(errorMessage: String?, promise: Promise) {
|
|
175
|
+
listener.handleResumeFailure(errorMessage.orEmpty(), promise)
|
|
176
|
+
}
|
|
177
|
+
// endregion
|
|
178
|
+
|
|
179
|
+
// region payment handlers
|
|
180
|
+
@ReactMethod
|
|
181
|
+
fun handlePaymentCreationContinue(promise: Promise) {
|
|
182
|
+
listener.handlePaymentCreationContinue()
|
|
183
|
+
promise.resolve(null)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@ReactMethod
|
|
187
|
+
fun handlePaymentCreationAbort(errorMessage: String?, promise: Promise) {
|
|
188
|
+
listener.handlePaymentCreationAbort(errorMessage.orEmpty())
|
|
189
|
+
promise.resolve(null)
|
|
190
|
+
}
|
|
191
|
+
// endregion
|
|
192
|
+
|
|
193
|
+
@ReactMethod
|
|
194
|
+
fun setImplementedRNCallbacks(implementedRNCallbacksStr: String, promise: Promise) {
|
|
195
|
+
try {
|
|
196
|
+
Log.d(TAG, "implementedRNCallbacks: $implementedRNCallbacksStr")
|
|
197
|
+
val implementedRNCallbacks =
|
|
198
|
+
json.decodeFromString<PrimerHeadlessUniversalCheckoutImplementedRNCallbacks>(
|
|
199
|
+
implementedRNCallbacksStr
|
|
200
|
+
)
|
|
201
|
+
listener.setImplementedCallbacks(implementedRNCallbacks)
|
|
202
|
+
promise.resolve(null)
|
|
203
|
+
} catch (e: Exception) {
|
|
204
|
+
val exception =
|
|
205
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "Implemented callbacks $implementedRNCallbacksStr is not valid."
|
|
206
|
+
onError(exception)
|
|
207
|
+
promise.reject(exception.errorId, exception.description, e)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private fun onError(exception: PrimerErrorRN, checkoutDataRN: PrimerCheckoutDataRN? = null) {
|
|
212
|
+
val params = Arguments.createMap()
|
|
213
|
+
val errorJson = JSONObject(Json.encodeToString(exception))
|
|
214
|
+
val errorData = prepareData(errorJson)
|
|
215
|
+
params.putMap(Keys.ERROR, errorData)
|
|
216
|
+
checkoutDataRN?.let {
|
|
217
|
+
val checkoutDataJson = JSONObject(Json.encodeToString(it))
|
|
218
|
+
val checkoutData = prepareData(checkoutDataJson)
|
|
219
|
+
params.putMap(Keys.CHECKOUT_DATA, checkoutData)
|
|
220
|
+
}
|
|
221
|
+
sendEvent(PrimerHeadlessUniversalCheckoutEvent.ON_ERROR.eventName, params)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private fun sendEvent(name: String, params: WritableMap) {
|
|
225
|
+
reactApplicationContext.getJSModule(
|
|
226
|
+
DeviceEventManagerModule.RCTDeviceEventEmitter::class.java
|
|
227
|
+
).emit(name, params)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private fun sendEvent(name: String, data: JSONObject?) {
|
|
231
|
+
val params = prepareData(data)
|
|
232
|
+
reactApplicationContext.getJSModule(
|
|
233
|
+
DeviceEventManagerModule.RCTDeviceEventEmitter::class.java
|
|
234
|
+
).emit(name, params)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private fun prepareData(data: JSONObject?): WritableMap {
|
|
238
|
+
return data?.let { convertJsonToMap(data) } ?: Arguments.createMap()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private companion object {
|
|
242
|
+
const val TAG = "PrimerHUC"
|
|
243
|
+
}
|
|
244
|
+
}
|
package/android/src/main/java/com/primerioreactnative/PrimerRNHeadlessUniversalCheckoutListener.kt
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
package com.primerioreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.Callback
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import com.primerioreactnative.datamodels.*
|
|
7
|
+
import com.primerioreactnative.extensions.toPrimerCheckoutDataRN
|
|
8
|
+
import com.primerioreactnative.extensions.toPrimerClientSessionRN
|
|
9
|
+
import com.primerioreactnative.extensions.toPrimerPaymentMethodDataRN
|
|
10
|
+
import com.primerioreactnative.huc.events.PrimerHeadlessUniversalCheckoutEvent
|
|
11
|
+
import com.primerioreactnative.utils.PrimerHeadlessUniversalCheckoutImplementedRNCallbacks
|
|
12
|
+
import com.primerioreactnative.utils.errorTo
|
|
13
|
+
import io.primer.android.ExperimentalPrimerApi
|
|
14
|
+
import io.primer.android.completion.PrimerPaymentCreationDecisionHandler
|
|
15
|
+
import io.primer.android.completion.PrimerResumeDecisionHandler
|
|
16
|
+
import io.primer.android.components.PrimerHeadlessUniversalCheckoutListener
|
|
17
|
+
import io.primer.android.components.domain.core.models.PrimerHeadlessUniversalCheckoutPaymentMethod
|
|
18
|
+
import io.primer.android.data.configuration.models.PrimerPaymentMethodType
|
|
19
|
+
import io.primer.android.domain.PrimerCheckoutData
|
|
20
|
+
import io.primer.android.domain.action.models.PrimerClientSession
|
|
21
|
+
import io.primer.android.domain.error.models.PrimerError
|
|
22
|
+
import io.primer.android.domain.tokenization.models.PrimerPaymentMethodData
|
|
23
|
+
import io.primer.android.domain.tokenization.models.PrimerPaymentMethodTokenData
|
|
24
|
+
import kotlinx.serialization.encodeToString
|
|
25
|
+
import kotlinx.serialization.json.Json
|
|
26
|
+
import org.json.JSONObject
|
|
27
|
+
|
|
28
|
+
@OptIn(ExperimentalPrimerApi::class)
|
|
29
|
+
class PrimerRNHeadlessUniversalCheckoutListener : PrimerHeadlessUniversalCheckoutListener {
|
|
30
|
+
private var paymentCreationDecisionHandler: ((errorMessage: String?) -> Unit)? = null
|
|
31
|
+
private var tokenizeSuccessDecisionHandler: ((resumeToken: String?, errorMessage: String?) -> Unit)? =
|
|
32
|
+
null
|
|
33
|
+
private var resumeSuccessDecisionHandler: ((resumeToken: String?, errorMessage: String?) -> Unit)? =
|
|
34
|
+
null
|
|
35
|
+
private var implementedRNCallbacks: PrimerHeadlessUniversalCheckoutImplementedRNCallbacks? = null
|
|
36
|
+
|
|
37
|
+
var sendEvent: ((eventName: String, paramsJson: JSONObject?) -> Unit)? = null
|
|
38
|
+
|
|
39
|
+
var sendError: ((error: PrimerErrorRN) -> Unit)? = null
|
|
40
|
+
var sendErrorWithCheckoutData: ((error: PrimerErrorRN, checkoutData: PrimerCheckoutDataRN?) -> Unit)? =
|
|
41
|
+
null
|
|
42
|
+
|
|
43
|
+
var successCallback: Callback? = null
|
|
44
|
+
|
|
45
|
+
override fun onAvailablePaymentMethodsLoaded(paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>) {
|
|
46
|
+
sendEvent?.invoke(
|
|
47
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_HUC_AVAILABLE_PAYMENT_METHODS_LOADED.eventName,
|
|
48
|
+
JSONObject().apply {
|
|
49
|
+
put("paymentMethodTypes", paymentMethods.map { it.paymentMethodType.name })
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
successCallback?.invoke(
|
|
53
|
+
Arguments.fromList(paymentMethods.map { it.paymentMethodType.name })
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override fun onPreparationStarted(paymentMethodType: PrimerPaymentMethodType) {
|
|
58
|
+
sendEvent?.invoke(
|
|
59
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_HUC_PREPARE_START.eventName,
|
|
60
|
+
JSONObject(Json.encodeToString(PrimerPaymentMethodDataRN(paymentMethodType)))
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun onPaymentMethodShowed(paymentMethodType: PrimerPaymentMethodType) {
|
|
65
|
+
sendEvent?.invoke(
|
|
66
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_HUC_PAYMENT_METHOD_SHOW.eventName,
|
|
67
|
+
JSONObject(Json.encodeToString(PrimerPaymentMethodDataRN(paymentMethodType)))
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun onTokenizationStarted(paymentMethodType: PrimerPaymentMethodType) {
|
|
72
|
+
sendEvent?.invoke(
|
|
73
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_HUC_TOKENIZE_START.eventName,
|
|
74
|
+
JSONObject(Json.encodeToString(PrimerPaymentMethodDataRN(paymentMethodType)))
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override fun onCheckoutCompleted(checkoutData: PrimerCheckoutData) {
|
|
79
|
+
if (implementedRNCallbacks?.isOnCheckoutCompleteImplemented == true) {
|
|
80
|
+
sendEvent?.invoke(
|
|
81
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_CHECKOUT_COMPLETE.eventName,
|
|
82
|
+
JSONObject(Json.encodeToString(checkoutData.toPrimerCheckoutDataRN()))
|
|
83
|
+
)
|
|
84
|
+
} else {
|
|
85
|
+
sendError?.invoke(
|
|
86
|
+
ErrorTypeRN.NativeBridgeFailed
|
|
87
|
+
errorTo "Callback [onCheckoutComplete] should be implemented."
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override fun onBeforePaymentCreated(
|
|
93
|
+
paymentMethodData: PrimerPaymentMethodData,
|
|
94
|
+
createPaymentHandler: PrimerPaymentCreationDecisionHandler
|
|
95
|
+
) {
|
|
96
|
+
if (implementedRNCallbacks?.isOnBeforePaymentCreateImplemented == true) {
|
|
97
|
+
paymentCreationDecisionHandler = { errorMessage ->
|
|
98
|
+
when {
|
|
99
|
+
errorMessage != null -> createPaymentHandler.abortPaymentCreation(errorMessage.ifBlank { null })
|
|
100
|
+
else -> createPaymentHandler.continuePaymentCreation()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
sendEvent?.invoke(
|
|
104
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_BEFORE_PAYMENT_CREATE.eventName,
|
|
105
|
+
JSONObject(Json.encodeToString(paymentMethodData.toPrimerPaymentMethodDataRN()))
|
|
106
|
+
)
|
|
107
|
+
} else {
|
|
108
|
+
super.onBeforePaymentCreated(paymentMethodData, createPaymentHandler)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override fun onBeforeClientSessionUpdated() {
|
|
113
|
+
if (implementedRNCallbacks?.isOnBeforeClientSessionUpdateImplemented == true) {
|
|
114
|
+
sendEvent?.invoke(
|
|
115
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_BEFORE_CLIENT_SESSION_UPDATE.eventName,
|
|
116
|
+
null
|
|
117
|
+
)
|
|
118
|
+
} else {
|
|
119
|
+
super.onBeforeClientSessionUpdated()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun onClientSessionUpdated(clientSession: PrimerClientSession) {
|
|
124
|
+
if (implementedRNCallbacks?.isOnClientSessionUpdateImplemented == true) {
|
|
125
|
+
sendEvent?.invoke(
|
|
126
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_CLIENT_SESSION_UPDATE.eventName,
|
|
127
|
+
JSONObject(Json.encodeToString(clientSession.toPrimerClientSessionRN()))
|
|
128
|
+
)
|
|
129
|
+
} else {
|
|
130
|
+
super.onClientSessionUpdated(clientSession)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override fun onTokenizeSuccess(
|
|
135
|
+
paymentMethodTokenData: PrimerPaymentMethodTokenData,
|
|
136
|
+
decisionHandler: PrimerResumeDecisionHandler
|
|
137
|
+
) {
|
|
138
|
+
if (implementedRNCallbacks?.isOnTokenizeSuccessImplemented == true) {
|
|
139
|
+
val token = PrimerPaymentInstrumentTokenRN.fromPaymentMethodToken(paymentMethodTokenData)
|
|
140
|
+
val request = JSONObject(Json.encodeToString(token))
|
|
141
|
+
tokenizeSuccessDecisionHandler = { newClientToken, err ->
|
|
142
|
+
when {
|
|
143
|
+
err != null -> decisionHandler.handleFailure(err.ifBlank { null })
|
|
144
|
+
newClientToken != null -> decisionHandler.continueWithNewClientToken(newClientToken)
|
|
145
|
+
else -> decisionHandler.handleSuccess()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
sendEvent?.invoke(PrimerHeadlessUniversalCheckoutEvent.ON_TOKENIZE_SUCCESS.eventName, request)
|
|
149
|
+
} else {
|
|
150
|
+
sendError?.invoke(
|
|
151
|
+
ErrorTypeRN.NativeBridgeFailed
|
|
152
|
+
errorTo "Callback [onTokenizeSuccess] should be implemented."
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
override fun onResumeSuccess(
|
|
158
|
+
resumeToken: String,
|
|
159
|
+
decisionHandler: PrimerResumeDecisionHandler
|
|
160
|
+
) {
|
|
161
|
+
if (implementedRNCallbacks?.isOnResumeSuccessImplemented == true) {
|
|
162
|
+
resumeSuccessDecisionHandler = { newClientToken, err ->
|
|
163
|
+
when {
|
|
164
|
+
err != null -> decisionHandler.handleFailure(err.ifBlank { null })
|
|
165
|
+
newClientToken != null -> decisionHandler.continueWithNewClientToken(newClientToken)
|
|
166
|
+
else -> decisionHandler.handleSuccess()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
val resumeToken = mapOf(Keys.RESUME_TOKEN to resumeToken)
|
|
171
|
+
sendEvent?.invoke(
|
|
172
|
+
PrimerHeadlessUniversalCheckoutEvent.ON_RESUME_SUCCESS.eventName,
|
|
173
|
+
JSONObject(Json.encodeToString(resumeToken))
|
|
174
|
+
)
|
|
175
|
+
} else {
|
|
176
|
+
sendError?.invoke(
|
|
177
|
+
ErrorTypeRN.NativeBridgeFailed
|
|
178
|
+
errorTo "Callback [onResumeSuccess] should be implemented."
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
override fun onFailed(
|
|
184
|
+
error: PrimerError,
|
|
185
|
+
checkoutData: PrimerCheckoutData?,
|
|
186
|
+
) {
|
|
187
|
+
if (implementedRNCallbacks?.isOnErrorImplemented == true) {
|
|
188
|
+
sendErrorWithCheckoutData?.invoke(
|
|
189
|
+
PrimerErrorRN(
|
|
190
|
+
error.errorId,
|
|
191
|
+
error.description,
|
|
192
|
+
error.recoverySuggestion
|
|
193
|
+
), checkoutData?.toPrimerCheckoutDataRN()
|
|
194
|
+
)
|
|
195
|
+
} else {
|
|
196
|
+
super.onFailed(error, checkoutData)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
override fun onFailed(error: PrimerError) {
|
|
201
|
+
if (implementedRNCallbacks?.isOnErrorImplemented == true) {
|
|
202
|
+
sendError?.invoke(PrimerErrorRN(error.errorId, error.description, error.recoverySuggestion))
|
|
203
|
+
} else {
|
|
204
|
+
super.onFailed(error)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// region tokenization handlers
|
|
209
|
+
fun handleTokenizationNewClientToken(newClientToken: String) {
|
|
210
|
+
tokenizeSuccessDecisionHandler?.invoke(newClientToken, null)
|
|
211
|
+
tokenizeSuccessDecisionHandler = null
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fun handleTokenizationSuccess(promise: Promise) {
|
|
215
|
+
val error =
|
|
216
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "PrimerTokenizationHandler's " +
|
|
217
|
+
"handleSuccess function is not available on HUC."
|
|
218
|
+
promise.reject(error.errorId, error.description)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
fun handleTokenizationFailure(errorMessage: String, promise: Promise) {
|
|
222
|
+
val error =
|
|
223
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "PrimerTokenizationHandler's " +
|
|
224
|
+
"handleFailure function is not available on HUC."
|
|
225
|
+
promise.reject(error.errorId, error.description)
|
|
226
|
+
}
|
|
227
|
+
// endregion
|
|
228
|
+
|
|
229
|
+
// region resume handlers
|
|
230
|
+
fun handleResumeNewClientToken(newClientToken: String) {
|
|
231
|
+
resumeSuccessDecisionHandler?.invoke(newClientToken, null)
|
|
232
|
+
resumeSuccessDecisionHandler = null
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
fun handleResumeSuccess(promise: Promise) {
|
|
236
|
+
val error =
|
|
237
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "PrimerResumeHandler's " +
|
|
238
|
+
"handleSuccess function is not available on HUC."
|
|
239
|
+
promise.reject(error.errorId, error.description)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
fun handleResumeFailure(errorMessage: String, promise: Promise) {
|
|
243
|
+
val error =
|
|
244
|
+
ErrorTypeRN.NativeBridgeFailed errorTo "PrimerResumeHandler's " +
|
|
245
|
+
"handleFailure function is not available on HUC."
|
|
246
|
+
promise.reject(error.errorId, error.description)
|
|
247
|
+
}
|
|
248
|
+
// endregion
|
|
249
|
+
|
|
250
|
+
// region payment create handlers
|
|
251
|
+
fun handlePaymentCreationContinue() {
|
|
252
|
+
paymentCreationDecisionHandler?.invoke(null)
|
|
253
|
+
paymentCreationDecisionHandler = null
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fun handlePaymentCreationAbort(errorMessage: String) {
|
|
257
|
+
paymentCreationDecisionHandler?.invoke(errorMessage)
|
|
258
|
+
paymentCreationDecisionHandler = null
|
|
259
|
+
}
|
|
260
|
+
// endregion
|
|
261
|
+
|
|
262
|
+
fun setImplementedCallbacks(
|
|
263
|
+
implementedRNCallbacks:
|
|
264
|
+
PrimerHeadlessUniversalCheckoutImplementedRNCallbacks
|
|
265
|
+
) {
|
|
266
|
+
this.implementedRNCallbacks = implementedRNCallbacks
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
fun removeCallbacksAndHandlers() {
|
|
270
|
+
paymentCreationDecisionHandler = null
|
|
271
|
+
tokenizeSuccessDecisionHandler = null
|
|
272
|
+
resumeSuccessDecisionHandler = null
|
|
273
|
+
implementedRNCallbacks = null
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -4,15 +4,26 @@ import com.facebook.react.ReactPackage
|
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
6
|
import com.facebook.react.uimanager.ViewManager
|
|
7
|
-
|
|
7
|
+
import kotlinx.serialization.json.Json
|
|
8
8
|
|
|
9
9
|
class ReactNativePackage : ReactPackage {
|
|
10
|
+
|
|
11
|
+
private val json = Json { ignoreUnknownKeys = true }
|
|
12
|
+
|
|
10
13
|
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
11
|
-
return listOf(
|
|
14
|
+
return listOf(
|
|
15
|
+
PrimerRN(reactContext, json),
|
|
16
|
+
PrimerRNHeadlessUniversalCheckout(reactContext, json)
|
|
17
|
+
)
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
15
|
-
return
|
|
21
|
+
return mutableListOf(
|
|
22
|
+
PrimerCardNumberEditTextManager(),
|
|
23
|
+
PrimerCardholderNameEditTextManager(),
|
|
24
|
+
PrimerExpiryEditTextManager(),
|
|
25
|
+
PrimerCvvEditTextManager(),
|
|
26
|
+
)
|
|
16
27
|
}
|
|
17
28
|
}
|
|
18
29
|
|
|
@@ -12,4 +12,7 @@ data class PrimerErrorRN(
|
|
|
12
12
|
@Serializable
|
|
13
13
|
enum class ErrorTypeRN(val errorId: String) {
|
|
14
14
|
NativeBridgeFailed("native-bridge"),
|
|
15
|
+
AssetMissing("missing-asset"),
|
|
16
|
+
AssetMismatch("mismatch-asset"),
|
|
17
|
+
InvalidPaymentMethodType("invalid-payment-method-type")
|
|
15
18
|
}
|