@primer-io/react-native 0.6.4 → 0.6.8
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 +4 -6
- package/android/.gradle/7.0.2/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.0.2/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.0.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/7.0.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.0.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.0.2/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/checksums/checksums.lock +0 -0
- package/android/.gradle/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/primerioreactnative/PrimerRN.kt +34 -61
- package/android/src/main/java/com/primerioreactnative/PrimerRNEventListener.kt +21 -3
- package/android/src/main/java/com/primerioreactnative/datamodels/PrimerRequestRN.kt +2 -1
- package/android/src/main/java/com/primerioreactnative/datamodels/PrimerSettingsRN.kt +85 -12
- package/android/src/main/java/com/primerioreactnative/datamodels/PrimerThemeRN.kt +6 -14
- package/ios/DataModels/PrimerErrorRN.swift +4 -0
- package/ios/DataModels/PrimerRequestRN.swift +2 -1
- package/ios/DataModels/PrimerSettingsRN.swift +33 -5
- package/ios/PrimerRN+PrimerDelegate.swift +27 -2
- package/ios/PrimerRN.swift +11 -5
- package/ios/ReactNative.m +2 -0
- package/ios/ReactNative.xcodeproj/project.pbxproj +0 -44
- package/lib/commonjs/Primer.js +52 -4
- package/lib/commonjs/Primer.js.map +1 -1
- package/lib/commonjs/models/action-request.js +2 -0
- package/lib/commonjs/models/action-request.js.map +1 -0
- package/lib/module/Primer.js +52 -4
- package/lib/module/Primer.js.map +1 -1
- package/lib/module/models/action-request.js +2 -0
- package/lib/module/models/action-request.js.map +1 -0
- package/lib/typescript/models/action-request.d.ts +10 -0
- package/lib/typescript/models/primer-callbacks.d.ts +2 -0
- package/lib/typescript/models/primer-config.d.ts +1 -0
- package/lib/typescript/models/primer-request.d.ts +13 -2
- package/lib/typescript/models/primer-settings.d.ts +8 -6
- package/package.json +1 -1
- package/primer-io-react-native.podspec +1 -1
- package/src/Primer.ts +32 -3
- package/src/models/action-request.ts +12 -0
- package/src/models/primer-callbacks.ts +6 -0
- package/src/models/primer-config.ts +3 -0
- package/src/models/primer-request.ts +18 -2
- package/src/models/primer-settings.ts +8 -6
- package/ios/Podfile.lock +0 -3
package/README.md
CHANGED
|
@@ -43,15 +43,13 @@ import { Primer } from '@primer-io/react-native';
|
|
|
43
43
|
const token: string = await fetchClientToken();
|
|
44
44
|
|
|
45
45
|
// configure listeners and settings.
|
|
46
|
-
const onTokenizeSuccess = (t, handler) => {
|
|
47
|
-
|
|
48
|
-
handler.
|
|
46
|
+
const onTokenizeSuccess = async (t, handler) => {
|
|
47
|
+
const payment = await createPayment(t);
|
|
48
|
+
handler.handleSuccess(); // resume the checkout flow with success message.
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const settings = { order: { amount: 50, currency: 'GBP' } };
|
|
52
|
-
|
|
53
51
|
// show Universal Checkout with client token and config.
|
|
54
|
-
Primer.showUniversalCheckout(token, { onTokenizeSuccess
|
|
52
|
+
Primer.showUniversalCheckout(token, { onTokenizeSuccess });
|
|
55
53
|
```
|
|
56
54
|
|
|
57
55
|
For more info & help troubleshooting, check out our 🔥 [docs](https://www.notion.so/primerio/Quick-Start-6c5eb61e5bbe426ca66244259e06048e)
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
package/android/build.gradle
CHANGED
|
@@ -128,5 +128,5 @@ dependencies {
|
|
|
128
128
|
api 'com.facebook.react:react-native:+'
|
|
129
129
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
130
130
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2"
|
|
131
|
-
implementation 'io.primer:android:1.
|
|
131
|
+
implementation 'io.primer:android:1.4.0'
|
|
132
132
|
}
|
|
@@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
|
8
8
|
import com.facebook.react.bridge.ReactMethod
|
|
9
9
|
import com.primerioreactnative.datamodels.*
|
|
10
10
|
import io.primer.android.Primer
|
|
11
|
+
import io.primer.android.model.dto.*
|
|
11
12
|
import kotlinx.serialization.decodeFromString
|
|
12
13
|
import kotlinx.serialization.encodeToString
|
|
13
14
|
import kotlinx.serialization.json.Json
|
|
@@ -87,6 +88,11 @@ class PrimerRN(reactContext: ReactApplicationContext) : ReactContextBaseJavaModu
|
|
|
87
88
|
mListener.configureOnTokenizeSuccess(callback)
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
@ReactMethod
|
|
92
|
+
fun configureOnResumeSuccess(callback: Callback) {
|
|
93
|
+
mListener.configureOnResumeSuccess(callback)
|
|
94
|
+
}
|
|
95
|
+
|
|
90
96
|
@ReactMethod
|
|
91
97
|
fun configureOnVaultSuccess(callback: Callback) {
|
|
92
98
|
mListener.configureOnVaultSuccess(callback)
|
|
@@ -113,9 +119,28 @@ class PrimerRN(reactContext: ReactApplicationContext) : ReactContextBaseJavaModu
|
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
private fun startSdk(token: String) {
|
|
116
|
-
val
|
|
117
|
-
val
|
|
118
|
-
|
|
122
|
+
val theme = theme.format()
|
|
123
|
+
val settings = settings.format()
|
|
124
|
+
val config = PrimerConfig(theme, settings)
|
|
125
|
+
|
|
126
|
+
// todo: refactor with next version
|
|
127
|
+
mListener.completion = { error, clientToken ->
|
|
128
|
+
currentActivity?.let {
|
|
129
|
+
it.runOnUiThread {
|
|
130
|
+
if (error != null) {
|
|
131
|
+
mListener.resumeHandler?.handleError(Error(error))
|
|
132
|
+
} else {
|
|
133
|
+
if (clientToken == null) {
|
|
134
|
+
mListener.resumeHandler?.handleSuccess()
|
|
135
|
+
} else {
|
|
136
|
+
mListener.resumeHandler?.handleNewClientToken(clientToken)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Primer.instance.configure(config, mListener)
|
|
119
144
|
sdkWasInitialised = true
|
|
120
145
|
}
|
|
121
146
|
|
|
@@ -125,28 +150,12 @@ class PrimerRN(reactContext: ReactApplicationContext) : ReactContextBaseJavaModu
|
|
|
125
150
|
|
|
126
151
|
if (!sdkWasInitialised) startSdk(token)
|
|
127
152
|
|
|
128
|
-
Primer.
|
|
129
|
-
try {
|
|
130
|
-
val paymentMethods = data.map { PrimerPaymentInstrumentTokenRN.fromPaymentMethodToken(it) }
|
|
131
|
-
val request = json.encodeToString(paymentMethods)
|
|
132
|
-
mListener.onSavedPaymentInstrumentsFetchedQueue?.addRequestAndPoll(request)
|
|
133
|
-
} catch (e: Exception) {
|
|
134
|
-
Log.e("PrimerRN", "fetch saved payment methods error: $e")
|
|
135
|
-
val exception = PrimerErrorRN(
|
|
136
|
-
ErrorTypeRN.ParseJsonFailed,
|
|
137
|
-
"failed to parse fetched payment methods.",
|
|
138
|
-
)
|
|
139
|
-
val encoded = json.encodeToString(exception)
|
|
140
|
-
mListener.onPrimerErrorQueue?.addRequestAndPoll(encoded)
|
|
141
|
-
haltExecution = true
|
|
142
|
-
}
|
|
143
|
-
}
|
|
153
|
+
Primer.instance.fetchSavedPaymentInstruments(token)
|
|
144
154
|
}
|
|
145
155
|
|
|
146
156
|
@ReactMethod
|
|
147
157
|
fun initialize(token: String) {
|
|
148
158
|
try {
|
|
149
|
-
|
|
150
159
|
if (haltExecution) {
|
|
151
160
|
haltExecution = false
|
|
152
161
|
return
|
|
@@ -154,50 +163,13 @@ class PrimerRN(reactContext: ReactApplicationContext) : ReactContextBaseJavaModu
|
|
|
154
163
|
|
|
155
164
|
Log.d("PrimerRN", "init with client token: $token")
|
|
156
165
|
|
|
157
|
-
val theme = this.theme.primerTheme
|
|
158
|
-
|
|
159
|
-
val context = currentActivity as Context
|
|
160
|
-
|
|
161
166
|
startSdk(token)
|
|
162
167
|
|
|
163
|
-
val
|
|
164
|
-
Primer.loadPaymentMethods(paymentMethods)
|
|
165
|
-
|
|
166
|
-
mListener.completion = { error ->
|
|
167
|
-
currentActivity?.let {
|
|
168
|
-
it.runOnUiThread {
|
|
169
|
-
if (error) {
|
|
170
|
-
Primer.showError()
|
|
171
|
-
} else {
|
|
172
|
-
Primer.showSuccess()
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
168
|
+
val context = currentActivity as Context
|
|
177
169
|
|
|
178
170
|
when (intent.vault) {
|
|
179
|
-
false -> Primer.
|
|
180
|
-
|
|
181
|
-
mListener,
|
|
182
|
-
isStandalonePaymentMethod = paymentMethods.size < 2,
|
|
183
|
-
doNotShowUi = !(settings.options?.isLoadingScreenEnabled ?: true),
|
|
184
|
-
preferWebView = true,
|
|
185
|
-
currency = settings.order?.currency,
|
|
186
|
-
amount = settings.order?.amount,
|
|
187
|
-
clearAllListeners = true,
|
|
188
|
-
webBrowserRedirectScheme = settings.options?.android?.redirectScheme,
|
|
189
|
-
)
|
|
190
|
-
true -> Primer.showVault(
|
|
191
|
-
context,
|
|
192
|
-
mListener,
|
|
193
|
-
isStandalonePaymentMethod = paymentMethods.size < 2,
|
|
194
|
-
doNotShowUi = !(settings.options?.isLoadingScreenEnabled ?: true),
|
|
195
|
-
preferWebView = true,
|
|
196
|
-
currency = settings.order?.currency,
|
|
197
|
-
amount = settings.order?.amount,
|
|
198
|
-
clearAllListeners = true,
|
|
199
|
-
webBrowserRedirectScheme = settings.options?.android?.redirectScheme,
|
|
200
|
-
)
|
|
171
|
+
false -> Primer.instance.showUniversalCheckout(context, token)
|
|
172
|
+
true -> Primer.instance.showVaultManager(context, token)
|
|
201
173
|
}
|
|
202
174
|
} catch (e: Exception) {
|
|
203
175
|
Log.e("PrimerRN", "init error: $e")
|
|
@@ -213,8 +185,9 @@ class PrimerRN(reactContext: ReactApplicationContext) : ReactContextBaseJavaModu
|
|
|
213
185
|
@ReactMethod
|
|
214
186
|
fun resume(request: String) {
|
|
215
187
|
try {
|
|
188
|
+
Log.d("PrimerRN", "resume: $request")
|
|
216
189
|
val data = json.decodeFromString<PrimerResumeRequest>(request)
|
|
217
|
-
mListener.completion?.invoke(data.error)
|
|
190
|
+
mListener.completion?.invoke(data.error, data.token)
|
|
218
191
|
} catch (e: Exception) {
|
|
219
192
|
Log.e("PrimerRN", "configure settings error: $e")
|
|
220
193
|
val exception = PrimerErrorRN(
|
|
@@ -7,7 +7,7 @@ import com.primerioreactnative.datamodels.PrimerErrorRN
|
|
|
7
7
|
import com.primerioreactnative.datamodels.PrimerPaymentInstrumentTokenRN
|
|
8
8
|
import com.primerioreactnative.utils.PrimerEventQueueRN
|
|
9
9
|
import io.primer.android.CheckoutEventListener
|
|
10
|
-
import io.primer.android.
|
|
10
|
+
import io.primer.android.completion.ResumeHandler
|
|
11
11
|
import io.primer.android.events.CheckoutEvent
|
|
12
12
|
import kotlinx.serialization.encodeToString
|
|
13
13
|
import kotlinx.serialization.json.Json
|
|
@@ -15,18 +15,26 @@ import kotlinx.serialization.json.Json
|
|
|
15
15
|
class PrimerRNEventListener : CheckoutEventListener {
|
|
16
16
|
|
|
17
17
|
private var onTokenizeSuccessQueue: PrimerEventQueueRN? = null
|
|
18
|
+
private var onResumeSuccessQueue: PrimerEventQueueRN? = null
|
|
18
19
|
private var onVaultSuccessQueue: PrimerEventQueueRN? = null
|
|
19
20
|
private var onDismissQueue: PrimerEventQueueRN? = null
|
|
20
21
|
var onPrimerErrorQueue: PrimerEventQueueRN? = null
|
|
21
22
|
var onSavedPaymentInstrumentsFetchedQueue: PrimerEventQueueRN? = null
|
|
22
23
|
|
|
23
|
-
var completion: ((error:
|
|
24
|
+
var completion: ((error: String?, token: String?) -> Unit)? = null
|
|
25
|
+
|
|
26
|
+
var resumeHandler: ResumeHandler? = null
|
|
24
27
|
|
|
25
28
|
fun configureOnTokenizeSuccess(callback: Callback) {
|
|
26
29
|
onTokenizeSuccessQueue = PrimerEventQueueRN()
|
|
27
30
|
onTokenizeSuccessQueue?.poll(callback)
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
fun configureOnResumeSuccess(callback: Callback) {
|
|
34
|
+
onResumeSuccessQueue = PrimerEventQueueRN()
|
|
35
|
+
onResumeSuccessQueue?.poll(callback)
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
fun configureOnVaultSuccess(callback: Callback) {
|
|
31
39
|
onVaultSuccessQueue = PrimerEventQueueRN()
|
|
32
40
|
onVaultSuccessQueue?.poll(callback)
|
|
@@ -58,14 +66,24 @@ class PrimerRNEventListener : CheckoutEventListener {
|
|
|
58
66
|
val token = PrimerPaymentInstrumentTokenRN.fromPaymentMethodToken(e.data)
|
|
59
67
|
val request = Json.encodeToString(token)
|
|
60
68
|
onTokenizeSuccessQueue?.addRequestAndPoll(request)
|
|
69
|
+
resumeHandler = e.resumeHandler
|
|
61
70
|
}
|
|
62
71
|
is CheckoutEvent.TokenSelected -> {
|
|
63
72
|
val token = PrimerPaymentInstrumentTokenRN.fromPaymentMethodToken(e.data)
|
|
64
73
|
val request = Json.encodeToString(token)
|
|
65
74
|
onTokenizeSuccessQueue?.addRequestAndPoll(request)
|
|
66
75
|
}
|
|
76
|
+
is CheckoutEvent.ResumeSuccess -> {
|
|
77
|
+
val token = e.resumeToken
|
|
78
|
+
onResumeSuccessQueue?.addRequestAndPoll(token)
|
|
79
|
+
resumeHandler = e.resumeHandler
|
|
80
|
+
}
|
|
81
|
+
is CheckoutEvent.SavedPaymentInstrumentsFetched -> {
|
|
82
|
+
val list = e.data.map { PrimerPaymentInstrumentTokenRN.fromPaymentMethodToken(it) }
|
|
83
|
+
val request = Json.encodeToString(list)
|
|
84
|
+
onSavedPaymentInstrumentsFetchedQueue?.addRequestAndPoll(request)
|
|
85
|
+
}
|
|
67
86
|
is CheckoutEvent.Exit -> {
|
|
68
|
-
println("🔥 exit event ${e.data}")
|
|
69
87
|
onDismissQueue?.addRequestAndPoll("dismiss")
|
|
70
88
|
onDismissQueue = null
|
|
71
89
|
}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
package com.primerioreactnative.datamodels
|
|
2
2
|
|
|
3
|
+
import io.primer.android.model.PrimerDebugOptions
|
|
4
|
+
import io.primer.android.model.dto.*
|
|
3
5
|
import kotlinx.serialization.Serializable
|
|
4
6
|
|
|
5
7
|
@Serializable
|
|
6
8
|
class PrimerSettingsRN(
|
|
7
9
|
val order: OrderRN? = null,
|
|
8
10
|
val business: BusinessRN? = null,
|
|
9
|
-
val customer: CustomerRN? = null,
|
|
10
|
-
val options: OptionsRN? = null,
|
|
11
|
-
)
|
|
11
|
+
private val customer: CustomerRN? = null,
|
|
12
|
+
private val options: OptionsRN? = null,
|
|
13
|
+
) {
|
|
14
|
+
fun format(): PrimerSettings {
|
|
15
|
+
val order = order?.format() ?: Order()
|
|
16
|
+
val customer = customer?.format() ?: Customer()
|
|
17
|
+
val business = business?.format() ?: Business()
|
|
18
|
+
val options = options?.format() ?: Options()
|
|
19
|
+
return PrimerSettings(order, customer, business, options)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
12
22
|
|
|
13
23
|
@Serializable
|
|
14
24
|
data class OrderRN(
|
|
@@ -17,7 +27,16 @@ data class OrderRN(
|
|
|
17
27
|
val countryCode: String? = null,
|
|
18
28
|
val items: List<OrderItemRN>? = null,
|
|
19
29
|
val shipping: PrimerAddressRN? = null,
|
|
20
|
-
)
|
|
30
|
+
) {
|
|
31
|
+
fun format(): Order {
|
|
32
|
+
return Order(
|
|
33
|
+
amount = amount,
|
|
34
|
+
currency = currency,
|
|
35
|
+
countryCode = countryCode?.let { CountryCode.valueOf(it) },
|
|
36
|
+
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
21
40
|
|
|
22
41
|
@Serializable
|
|
23
42
|
data class OrderItemRN(
|
|
@@ -34,7 +53,18 @@ data class BusinessRN(
|
|
|
34
53
|
val email: String? = null,
|
|
35
54
|
val phone: String? = null,
|
|
36
55
|
val address: PrimerAddressRN? = null,
|
|
37
|
-
)
|
|
56
|
+
) {
|
|
57
|
+
|
|
58
|
+
fun format(): Business {
|
|
59
|
+
return Business(
|
|
60
|
+
name = name,
|
|
61
|
+
registrationNumber = registrationNumber,
|
|
62
|
+
email = email,
|
|
63
|
+
phone = phone,
|
|
64
|
+
address = address?.format(),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
38
68
|
|
|
39
69
|
@Serializable
|
|
40
70
|
data class CustomerRN(
|
|
@@ -44,16 +74,39 @@ data class CustomerRN(
|
|
|
44
74
|
val email: String? = null,
|
|
45
75
|
val phone: String? = null,
|
|
46
76
|
val billing: PrimerAddressRN? = null,
|
|
47
|
-
)
|
|
77
|
+
) {
|
|
78
|
+
fun format(): Customer {
|
|
79
|
+
return Customer(
|
|
80
|
+
id = id,
|
|
81
|
+
firstName = firstName,
|
|
82
|
+
lastName = lastName,
|
|
83
|
+
email = email,
|
|
84
|
+
homePhone = phone,
|
|
85
|
+
billingAddress = billing?.format(),
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
48
89
|
|
|
49
90
|
@Serializable
|
|
50
91
|
data class OptionsRN(
|
|
51
92
|
val isResultScreenEnabled: Boolean? = null,
|
|
52
93
|
val isLoadingScreenEnabled: Boolean? = null,
|
|
53
94
|
val isFullScreenEnabled: Boolean? = null,
|
|
95
|
+
val isThreeDsEnabled: Boolean? = null,
|
|
54
96
|
val locale: String? = null,
|
|
55
97
|
val android: AndroidOptionsRN? = null,
|
|
56
|
-
)
|
|
98
|
+
) {
|
|
99
|
+
fun format(): Options {
|
|
100
|
+
return Options(
|
|
101
|
+
showUI = isLoadingScreenEnabled ?: true,
|
|
102
|
+
redirectScheme = android?.redirectScheme,
|
|
103
|
+
is3DSOnVaultingEnabled = isThreeDsEnabled ?: false,
|
|
104
|
+
debugOptions = PrimerDebugOptions(
|
|
105
|
+
is3DSSanityCheckEnabled = true, // false on emulator
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
57
110
|
|
|
58
111
|
@Serializable
|
|
59
112
|
data class AndroidOptionsRN(
|
|
@@ -62,10 +115,30 @@ data class AndroidOptionsRN(
|
|
|
62
115
|
|
|
63
116
|
@Serializable
|
|
64
117
|
data class PrimerAddressRN(
|
|
65
|
-
val line1: String
|
|
118
|
+
val line1: String?,
|
|
66
119
|
val line2: String? = null,
|
|
67
|
-
val postalCode: String
|
|
120
|
+
val postalCode: String?,
|
|
68
121
|
val state: String? = null,
|
|
69
|
-
val city: String
|
|
70
|
-
val country: String
|
|
71
|
-
)
|
|
122
|
+
val city: String?,
|
|
123
|
+
val country: String?,
|
|
124
|
+
) {
|
|
125
|
+
|
|
126
|
+
fun format(): Address? {
|
|
127
|
+
if (
|
|
128
|
+
line1 == null ||
|
|
129
|
+
postalCode == null ||
|
|
130
|
+
city == null ||
|
|
131
|
+
country == null
|
|
132
|
+
) {
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return Address(
|
|
137
|
+
line1 = line1,
|
|
138
|
+
line2 = line2,
|
|
139
|
+
city = city,
|
|
140
|
+
countryCode = CountryCode.valueOf(country),
|
|
141
|
+
postalCode = postalCode,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.primerioreactnative.datamodels
|
|
2
2
|
|
|
3
|
-
import io.primer.android.
|
|
3
|
+
import io.primer.android.InputThemeData
|
|
4
|
+
import io.primer.android.PrimerTheme
|
|
4
5
|
import kotlinx.serialization.Serializable
|
|
5
6
|
|
|
6
7
|
@Serializable
|
|
@@ -8,20 +9,11 @@ class PrimerThemeRN(
|
|
|
8
9
|
private val colors: ColorThemeRN? = null,
|
|
9
10
|
val darkModeColors: ColorThemeRN? = null,
|
|
10
11
|
) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
textDefaultColor = colors?.text?.hex,
|
|
15
|
-
textDangerColor = colors?.error?.hex,
|
|
16
|
-
textMutedColor = colors?.disabled?.hex,
|
|
17
|
-
backgroundColor = colors?.background?.hex,
|
|
18
|
-
buttonPrimaryColor = colors?.mainColor?.hex,
|
|
19
|
-
buttonPrimaryColorDisabled = colors?.disabled?.hex,
|
|
20
|
-
primaryColor = colors?.mainColor?.hex,
|
|
21
|
-
inputBackgroundColor = colors?.background?.hex,
|
|
22
|
-
buttonDefaultBorderColor = colors?.borders?.hex,
|
|
12
|
+
fun format(): PrimerTheme {
|
|
13
|
+
return PrimerTheme.build(
|
|
14
|
+
input = InputThemeData()
|
|
23
15
|
)
|
|
24
|
-
|
|
16
|
+
}
|
|
25
17
|
}
|
|
26
18
|
|
|
27
19
|
@Serializable
|
|
@@ -9,6 +9,18 @@ struct PrimerSettingsRN: Decodable {
|
|
|
9
9
|
|
|
10
10
|
extension PrimerSettingsRN {
|
|
11
11
|
func asPrimerSettings() -> PrimerSettings {
|
|
12
|
+
var address: Address?
|
|
13
|
+
if let billingAddress = customer?.billing {
|
|
14
|
+
address = Address(
|
|
15
|
+
addressLine1: billingAddress.line1,
|
|
16
|
+
addressLine2: billingAddress.line2,
|
|
17
|
+
city: billingAddress.city,
|
|
18
|
+
state: billingAddress.state,
|
|
19
|
+
countryCode: billingAddress.country?.rawValue,
|
|
20
|
+
postalCode: billingAddress.postalCode
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
return PrimerSettings(
|
|
13
25
|
merchantIdentifier: options?.ios?.merchantIdentifier,
|
|
14
26
|
customerId: customer?.id,
|
|
@@ -22,14 +34,26 @@ extension PrimerSettingsRN {
|
|
|
22
34
|
hasDisabledSuccessScreen: !(options?.isResultScreenEnabled ?? true),
|
|
23
35
|
businessDetails: business?.primerFormat,
|
|
24
36
|
orderItems: order?.itemsFormatted ?? [],
|
|
25
|
-
isInitialLoadingHidden: !(options?.isLoadingScreenEnabled ?? true)
|
|
37
|
+
isInitialLoadingHidden: !(options?.isLoadingScreenEnabled ?? true),
|
|
38
|
+
orderId: order?.id,
|
|
39
|
+
customer: Customer(
|
|
40
|
+
firstName: customer?.firstName,
|
|
41
|
+
lastName: customer?.lastName,
|
|
42
|
+
email: customer?.email,
|
|
43
|
+
homePhoneNumber: nil,
|
|
44
|
+
mobilePhoneNumber: customer?.phone,
|
|
45
|
+
workPhoneNumber: nil,
|
|
46
|
+
billingAddress: address
|
|
47
|
+
)
|
|
26
48
|
)
|
|
27
49
|
}
|
|
28
50
|
}
|
|
29
51
|
|
|
30
52
|
fileprivate struct OrderRN: Decodable {
|
|
53
|
+
let id: String?
|
|
31
54
|
let amount: Int?
|
|
32
55
|
let currency: Currency?
|
|
56
|
+
// FIXME: Move countryCode only within Address (RN & Android)
|
|
33
57
|
let countryCode: CountryCode?
|
|
34
58
|
let items: [OrderItemRN]?
|
|
35
59
|
let shipping: AddressRN?
|
|
@@ -70,11 +94,15 @@ fileprivate struct BusinessRN: Decodable {
|
|
|
70
94
|
let registrationNumber: String?
|
|
71
95
|
let email: String?
|
|
72
96
|
let phone: String?
|
|
73
|
-
let address: AddressRN
|
|
97
|
+
let address: AddressRN?
|
|
74
98
|
}
|
|
75
99
|
|
|
76
100
|
fileprivate extension BusinessRN {
|
|
77
|
-
var primerFormat: BusinessDetails {
|
|
101
|
+
var primerFormat: BusinessDetails? {
|
|
102
|
+
guard let address = address else {
|
|
103
|
+
return nil
|
|
104
|
+
}
|
|
105
|
+
|
|
78
106
|
return BusinessDetails(
|
|
79
107
|
name: name,
|
|
80
108
|
address: address.primerFormat
|
|
@@ -97,7 +125,7 @@ fileprivate struct AddressRN: Decodable {
|
|
|
97
125
|
let postalCode: String?
|
|
98
126
|
let city: String?
|
|
99
127
|
let state: String?
|
|
100
|
-
let country:
|
|
128
|
+
let country: CountryCode?
|
|
101
129
|
}
|
|
102
130
|
|
|
103
131
|
fileprivate extension AddressRN {
|
|
@@ -107,7 +135,7 @@ fileprivate extension AddressRN {
|
|
|
107
135
|
addressLine2: line2,
|
|
108
136
|
city: city,
|
|
109
137
|
state: state,
|
|
110
|
-
countryCode: country,
|
|
138
|
+
countryCode: country?.rawValue,
|
|
111
139
|
postalCode: postalCode
|
|
112
140
|
)
|
|
113
141
|
}
|
|
@@ -17,7 +17,10 @@ extension PrimerRN: PrimerDelegate {
|
|
|
17
17
|
completion(clientToken, nil)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
func onTokenizeSuccess(
|
|
20
|
+
func onTokenizeSuccess(
|
|
21
|
+
_ paymentMethodToken: PaymentMethodToken,
|
|
22
|
+
resumeHandler: ResumeHandlerProtocol
|
|
23
|
+
) {
|
|
21
24
|
do {
|
|
22
25
|
let json = try encoder.encode(paymentMethodToken)
|
|
23
26
|
let data = String(data: json, encoding: .utf8)!
|
|
@@ -25,7 +28,29 @@ extension PrimerRN: PrimerDelegate {
|
|
|
25
28
|
} catch {
|
|
26
29
|
checkoutFailed(with: ErrorTypeRN.ParseJsonFailed)
|
|
27
30
|
}
|
|
28
|
-
onResumeFlowCallback =
|
|
31
|
+
onResumeFlowCallback = { error, clientToken in
|
|
32
|
+
if let error = error {
|
|
33
|
+
resumeHandler.handle(error: error)
|
|
34
|
+
} else if let clientToken = clientToken {
|
|
35
|
+
resumeHandler.handle(newClientToken: clientToken)
|
|
36
|
+
} else {
|
|
37
|
+
resumeHandler.handleSuccess()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func onResumeSuccess(_ clientToken: String, resumeHandler: ResumeHandlerProtocol) {
|
|
43
|
+
self.onResumeSuccessCallback?([clientToken])
|
|
44
|
+
|
|
45
|
+
onResumeFlowCallback = { error, clientToken in
|
|
46
|
+
if let error = error {
|
|
47
|
+
resumeHandler.handle(error: error)
|
|
48
|
+
} else if let clientToken = clientToken {
|
|
49
|
+
resumeHandler.handle(newClientToken: clientToken)
|
|
50
|
+
} else {
|
|
51
|
+
resumeHandler.handleSuccess()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
29
54
|
}
|
|
30
55
|
|
|
31
56
|
func tokenAddedToVault(_ token: PaymentMethodToken) {
|
package/ios/PrimerRN.swift
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import UIKit
|
|
2
2
|
import PrimerSDK
|
|
3
3
|
|
|
4
|
-
typealias BasicCompletionBlock = ((Error?) -> Void)
|
|
4
|
+
typealias BasicCompletionBlock = ((Error?, String?) -> Void)
|
|
5
5
|
|
|
6
6
|
@objc(PrimerRN)
|
|
7
7
|
class PrimerRN: NSObject {
|
|
@@ -17,6 +17,7 @@ class PrimerRN: NSObject {
|
|
|
17
17
|
var theme: PrimerThemeRN?
|
|
18
18
|
var flow: PrimerSessionFlow?
|
|
19
19
|
var onTokenizeSuccessCallback: RCTResponseSenderBlock?
|
|
20
|
+
var onResumeSuccessCallback: RCTResponseSenderBlock?
|
|
20
21
|
var onVaultSuccessCallback: RCTResponseSenderBlock?
|
|
21
22
|
var onDismissCallback: RCTResponseSenderBlock?
|
|
22
23
|
var onPrimerErrorCallback: RCTResponseSenderBlock?
|
|
@@ -60,6 +61,10 @@ class PrimerRN: NSObject {
|
|
|
60
61
|
self.onTokenizeSuccessCallback = callback
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
@objc func configureOnResumeSuccess(_ callback: @escaping RCTResponseSenderBlock) {
|
|
65
|
+
self.onResumeSuccessCallback = callback
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
@objc func configureOnVaultSuccess(_ callback: @escaping RCTResponseSenderBlock) {
|
|
64
69
|
self.onVaultSuccessCallback = callback
|
|
65
70
|
}
|
|
@@ -122,7 +127,6 @@ class PrimerRN: NSObject {
|
|
|
122
127
|
Primer.shared.delegate = self
|
|
123
128
|
Primer.shared.configure(settings: settings, theme: theme)
|
|
124
129
|
Primer.shared.showCheckout(viewController, flow: flow)
|
|
125
|
-
|
|
126
130
|
} catch {
|
|
127
131
|
self?.checkoutFailed(with: error)
|
|
128
132
|
}
|
|
@@ -135,10 +139,12 @@ class PrimerRN: NSObject {
|
|
|
135
139
|
let json = request.data(using: .utf8)!
|
|
136
140
|
let request = try JSONDecoder().decode(PrimerResumeRequest.self, from: json)
|
|
137
141
|
|
|
138
|
-
if
|
|
139
|
-
self?.onResumeFlowCallback?(
|
|
142
|
+
if let error = request.error {
|
|
143
|
+
self?.onResumeFlowCallback?(ErrorRN(message: error), nil)
|
|
144
|
+
} else if let clientToken = request.token {
|
|
145
|
+
self?.onResumeFlowCallback?(nil, clientToken)
|
|
140
146
|
} else {
|
|
141
|
-
self?.onResumeFlowCallback?(nil)
|
|
147
|
+
self?.onResumeFlowCallback?(nil, nil)
|
|
142
148
|
}
|
|
143
149
|
self?.onResumeFlowCallback = nil
|
|
144
150
|
} catch {
|
package/ios/ReactNative.m
CHANGED
|
@@ -11,6 +11,8 @@ RCT_EXTERN_METHOD(configureIntent: (NSString *)request)
|
|
|
11
11
|
|
|
12
12
|
RCT_EXTERN_METHOD(configureOnTokenizeSuccess: (RCTResponseSenderBlock)callback)
|
|
13
13
|
|
|
14
|
+
RCT_EXTERN_METHOD(configureOnResumeSuccess: (RCTResponseSenderBlock)callback)
|
|
15
|
+
|
|
14
16
|
RCT_EXTERN_METHOD(configureOnVaultSuccess: (RCTResponseSenderBlock)callback)
|
|
15
17
|
|
|
16
18
|
RCT_EXTERN_METHOD(configureOnDismiss: (RCTResponseSenderBlock)callback)
|