@stripe/stripe-react-native 0.16.0 → 0.18.1
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/.husky/pre-commit +4 -0
- package/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/android/build.gradle +1 -1
- package/android/gradle.properties +2 -2
- package/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +1 -1
- package/android/src/main/java/com/reactnativestripesdk/CollectBankAccountLauncherFragment.kt +8 -1
- package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetFragment.kt +278 -0
- package/android/src/main/java/com/reactnativestripesdk/GooglePayFragment.kt +4 -0
- package/android/src/main/java/com/reactnativestripesdk/GooglePayPaymentMethodLauncherFragment.kt +6 -2
- package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +9 -11
- package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +2 -2
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +3 -1
- package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +59 -22
- package/android/src/main/java/com/reactnativestripesdk/utils/Errors.kt +4 -0
- package/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt +11 -0
- package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +5 -4
- package/ios/Errors.swift +12 -1
- package/ios/FinancialConnections.swift +258 -0
- package/ios/Mappers.swift +12 -9
- package/ios/StripeSdk.m +10 -1
- package/ios/StripeSdk.swift +51 -8
- package/lib/commonjs/NativeStripeSdk.js.map +1 -1
- package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
- package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
- package/lib/commonjs/components/CardForm.js +1 -1
- package/lib/commonjs/components/CardForm.js.map +1 -1
- package/lib/commonjs/components/StripeProvider.js +1 -1
- package/lib/commonjs/components/StripeProvider.js.map +1 -1
- package/lib/commonjs/functions.js +1 -1
- package/lib/commonjs/functions.js.map +1 -1
- package/lib/commonjs/hooks/useApplePay.js +1 -1
- package/lib/commonjs/hooks/useApplePay.js.map +1 -1
- package/lib/commonjs/hooks/useConfirmPayment.js +1 -1
- package/lib/commonjs/hooks/useConfirmPayment.js.map +1 -1
- package/lib/commonjs/hooks/useConfirmSetupIntent.js +1 -1
- package/lib/commonjs/hooks/useConfirmSetupIntent.js.map +1 -1
- package/lib/commonjs/hooks/useFinancialConnectionsSheet.js +2 -0
- package/lib/commonjs/hooks/useFinancialConnectionsSheet.js.map +1 -0
- package/lib/commonjs/hooks/useGooglePay.js +1 -1
- package/lib/commonjs/hooks/useGooglePay.js.map +1 -1
- package/lib/commonjs/hooks/usePaymentSheet.js +1 -1
- package/lib/commonjs/hooks/usePaymentSheet.js.map +1 -1
- package/lib/commonjs/hooks/useStripe.js +1 -1
- package/lib/commonjs/hooks/useStripe.js.map +1 -1
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/plugin/withStripe.js +1 -1
- package/lib/commonjs/plugin/withStripe.js.map +1 -1
- package/lib/commonjs/types/FinancialConnections.js +2 -0
- package/lib/commonjs/types/FinancialConnections.js.map +1 -0
- package/lib/commonjs/types/PaymentIntent.js.map +1 -1
- package/lib/commonjs/types/SetupIntent.js.map +1 -1
- package/lib/commonjs/types/index.js +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/module/NativeStripeSdk.js.map +1 -1
- package/lib/module/components/AuBECSDebitForm.js +1 -1
- package/lib/module/components/AuBECSDebitForm.js.map +1 -1
- package/lib/module/components/CardForm.js +1 -1
- package/lib/module/components/CardForm.js.map +1 -1
- package/lib/module/components/StripeProvider.js +1 -1
- package/lib/module/components/StripeProvider.js.map +1 -1
- package/lib/module/functions.js +1 -1
- package/lib/module/functions.js.map +1 -1
- package/lib/module/hooks/useApplePay.js +1 -1
- package/lib/module/hooks/useApplePay.js.map +1 -1
- package/lib/module/hooks/useConfirmPayment.js +1 -1
- package/lib/module/hooks/useConfirmPayment.js.map +1 -1
- package/lib/module/hooks/useConfirmSetupIntent.js +1 -1
- package/lib/module/hooks/useConfirmSetupIntent.js.map +1 -1
- package/lib/module/hooks/useFinancialConnectionsSheet.js +2 -0
- package/lib/module/hooks/useFinancialConnectionsSheet.js.map +1 -0
- package/lib/module/hooks/useGooglePay.js +1 -1
- package/lib/module/hooks/useGooglePay.js.map +1 -1
- package/lib/module/hooks/usePaymentSheet.js +1 -1
- package/lib/module/hooks/usePaymentSheet.js.map +1 -1
- package/lib/module/hooks/useStripe.js +1 -1
- package/lib/module/hooks/useStripe.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/plugin/withStripe.js +1 -1
- package/lib/module/plugin/withStripe.js.map +1 -1
- package/lib/module/types/FinancialConnections.js +2 -0
- package/lib/module/types/FinancialConnections.js.map +1 -0
- package/lib/module/types/PaymentIntent.js.map +1 -1
- package/lib/module/types/SetupIntent.js.map +1 -1
- package/lib/module/types/index.js +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/typescript/src/NativeStripeSdk.d.ts +4 -2
- package/lib/typescript/src/functions.d.ts +24 -2
- package/lib/typescript/src/hooks/useConfirmPayment.d.ts +2 -2
- package/lib/typescript/src/hooks/useFinancialConnectionsSheet.d.ts +11 -0
- package/lib/typescript/src/hooks/useStripe.d.ts +4 -2
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/types/FinancialConnections.d.ts +100 -0
- package/lib/typescript/src/types/PaymentIntent.d.ts +1 -0
- package/lib/typescript/src/types/SetupIntent.d.ts +1 -0
- package/lib/typescript/src/types/Token.d.ts +18 -7
- package/lib/typescript/src/types/index.d.ts +2 -1
- package/package.json +10 -12
- package/src/NativeStripeSdk.tsx +10 -2
- package/src/functions.ts +67 -1
- package/src/hooks/useConfirmPayment.tsx +3 -3
- package/src/hooks/useFinancialConnectionsSheet.tsx +34 -0
- package/src/hooks/useStripe.tsx +24 -2
- package/src/index.tsx +1 -0
- package/src/types/FinancialConnections.ts +126 -0
- package/src/types/PaymentIntent.ts +1 -0
- package/src/types/SetupIntent.ts +1 -0
- package/src/types/Token.ts +24 -7
- package/src/types/index.ts +2 -0
- package/stripe-react-native.podspec +1 -1
|
@@ -5,6 +5,7 @@ import android.content.Intent
|
|
|
5
5
|
import android.os.Parcelable
|
|
6
6
|
import android.util.Log
|
|
7
7
|
import androidx.appcompat.app.AppCompatActivity
|
|
8
|
+
import androidx.fragment.app.Fragment
|
|
8
9
|
import com.facebook.react.bridge.*
|
|
9
10
|
import com.facebook.react.module.annotations.ReactModule
|
|
10
11
|
import com.reactnativestripesdk.pushprovisioning.PushProvisioningProxy
|
|
@@ -36,21 +37,27 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
36
37
|
private var stripeAccountId: String? = null
|
|
37
38
|
private var urlScheme: String? = null
|
|
38
39
|
|
|
40
|
+
private var confirmPromise: Promise? = null
|
|
41
|
+
private var confirmPaymentClientSecret: String? = null
|
|
42
|
+
|
|
39
43
|
private var paymentSheetFragment: PaymentSheetFragment? = null
|
|
40
44
|
private var googlePayFragment: GooglePayFragment? = null
|
|
41
45
|
private var paymentLauncherFragment: PaymentLauncherFragment? = null
|
|
42
|
-
|
|
43
|
-
private var
|
|
44
|
-
private
|
|
46
|
+
private var collectBankAccountLauncherFragment: CollectBankAccountLauncherFragment? = null
|
|
47
|
+
private var financialConnectionsSheetFragment: FinancialConnectionsSheetFragment? = null
|
|
48
|
+
private val allFragments: List<Fragment?>
|
|
49
|
+
get() = listOf(
|
|
50
|
+
paymentSheetFragment,
|
|
51
|
+
googlePayFragment,
|
|
52
|
+
paymentLauncherFragment,
|
|
53
|
+
collectBankAccountLauncherFragment,
|
|
54
|
+
financialConnectionsSheetFragment
|
|
55
|
+
)
|
|
45
56
|
|
|
46
57
|
private val mActivityEventListener = object : BaseActivityEventListener() {
|
|
47
58
|
override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
|
|
48
59
|
if (::stripe.isInitialized) {
|
|
49
|
-
|
|
50
|
-
paymentSheetFragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
|
|
51
|
-
googlePayFragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
|
|
52
|
-
paymentLauncherFragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
|
|
53
|
-
// END
|
|
60
|
+
dispatchActivityResultsToFragments(requestCode, resultCode, data)
|
|
54
61
|
try {
|
|
55
62
|
val result = AddPaymentMethodActivityStarter.Result.fromIntent(data)
|
|
56
63
|
if (data?.getParcelableExtra<Parcelable>("extra_activity_result") != null) {
|
|
@@ -67,6 +74,13 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
67
74
|
reactContext.addActivityEventListener(mActivityEventListener)
|
|
68
75
|
}
|
|
69
76
|
|
|
77
|
+
// Necessary on older versions of React Native (~0.65 and below)
|
|
78
|
+
private fun dispatchActivityResultsToFragments(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
79
|
+
for (fragment in allFragments) {
|
|
80
|
+
fragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
70
84
|
private fun configure3dSecure(params: ReadableMap) {
|
|
71
85
|
val stripe3dsConfigBuilder = PaymentAuthConfig.Stripe3ds2Config.Builder()
|
|
72
86
|
if (params.hasKey("timeout")) stripe3dsConfigBuilder.setTimeout(params.getInt("timeout"))
|
|
@@ -121,17 +135,14 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
121
135
|
@ReactMethod
|
|
122
136
|
fun initPaymentSheet(params: ReadableMap, promise: Promise) {
|
|
123
137
|
getCurrentActivityOrResolveWithError(promise)?.let { activity ->
|
|
124
|
-
paymentSheetFragment?.
|
|
125
|
-
// If a payment sheet was already initialized, we want to remove its fragment first
|
|
126
|
-
activity.supportFragmentManager.beginTransaction().remove(it).commitAllowingStateLoss()
|
|
127
|
-
}
|
|
138
|
+
paymentSheetFragment?.removeFragment(reactApplicationContext)
|
|
128
139
|
paymentSheetFragment = PaymentSheetFragment(reactApplicationContext, promise).also {
|
|
129
140
|
val bundle = toBundleObject(params)
|
|
130
141
|
it.arguments = bundle
|
|
131
142
|
}
|
|
132
143
|
try {
|
|
133
144
|
activity.supportFragmentManager.beginTransaction()
|
|
134
|
-
.add(paymentSheetFragment!!,
|
|
145
|
+
.add(paymentSheetFragment!!, PaymentSheetFragment.TAG)
|
|
135
146
|
.commit()
|
|
136
147
|
} catch (error: IllegalStateException) {
|
|
137
148
|
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
|
|
@@ -368,12 +379,15 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
368
379
|
// }
|
|
369
380
|
|
|
370
381
|
@ReactMethod
|
|
371
|
-
fun confirmPayment(paymentIntentClientSecret: String, params: ReadableMap
|
|
382
|
+
fun confirmPayment(paymentIntentClientSecret: String, params: ReadableMap?, options: ReadableMap, promise: Promise) {
|
|
372
383
|
val paymentMethodData = getMapOrNull(params, "paymentMethodData")
|
|
373
|
-
val paymentMethodType =
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
384
|
+
val paymentMethodType = if (params != null)
|
|
385
|
+
mapToPaymentMethodType(params.getString("paymentMethodType")) ?: run {
|
|
386
|
+
promise.resolve(createError(ConfirmPaymentErrorType.Failed.toString(), "You must provide paymentMethodType"))
|
|
387
|
+
return
|
|
388
|
+
}
|
|
389
|
+
else
|
|
390
|
+
null // Expect that payment method was attached on the server
|
|
377
391
|
|
|
378
392
|
val testOfflineBank = getBooleanOrFalse(params, "testOfflineBank")
|
|
379
393
|
|
|
@@ -480,7 +494,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
480
494
|
getCurrentActivityOrResolveWithError(promise)?.let {
|
|
481
495
|
try {
|
|
482
496
|
it.supportFragmentManager.beginTransaction()
|
|
483
|
-
.add(fragment,
|
|
497
|
+
.add(fragment, GooglePayPaymentMethodLauncherFragment.TAG)
|
|
484
498
|
.commit()
|
|
485
499
|
} catch (error: IllegalStateException) {
|
|
486
500
|
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
|
|
@@ -498,7 +512,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
498
512
|
getCurrentActivityOrResolveWithError(promise)?.let {
|
|
499
513
|
try {
|
|
500
514
|
it.supportFragmentManager.beginTransaction()
|
|
501
|
-
.add(googlePayFragment!!,
|
|
515
|
+
.add(googlePayFragment!!, GooglePayFragment.TAG)
|
|
502
516
|
.commit()
|
|
503
517
|
} catch (error: IllegalStateException) {
|
|
504
518
|
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
|
|
@@ -603,9 +617,10 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
603
617
|
billingDetails.getString("email")
|
|
604
618
|
)
|
|
605
619
|
|
|
606
|
-
|
|
620
|
+
collectBankAccountLauncherFragment = CollectBankAccountLauncherFragment(
|
|
607
621
|
reactApplicationContext,
|
|
608
622
|
publishableKey,
|
|
623
|
+
stripeAccountId,
|
|
609
624
|
clientSecret,
|
|
610
625
|
isPaymentIntent,
|
|
611
626
|
collectParams,
|
|
@@ -614,7 +629,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
614
629
|
getCurrentActivityOrResolveWithError(promise)?.let {
|
|
615
630
|
try {
|
|
616
631
|
it.supportFragmentManager.beginTransaction()
|
|
617
|
-
.add(
|
|
632
|
+
.add(collectBankAccountLauncherFragment!!, "collect_bank_account_launcher_fragment")
|
|
618
633
|
.commit()
|
|
619
634
|
} catch (error: IllegalStateException) {
|
|
620
635
|
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
|
|
@@ -690,6 +705,28 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
690
705
|
}
|
|
691
706
|
}
|
|
692
707
|
|
|
708
|
+
@ReactMethod
|
|
709
|
+
fun collectBankAccountToken(clientSecret: String, promise: Promise) {
|
|
710
|
+
if (!::stripe.isInitialized) {
|
|
711
|
+
promise.resolve(createMissingInitError())
|
|
712
|
+
return
|
|
713
|
+
}
|
|
714
|
+
financialConnectionsSheetFragment = FinancialConnectionsSheetFragment().also {
|
|
715
|
+
it.presentFinancialConnectionsSheet(clientSecret, FinancialConnectionsSheetFragment.Mode.ForToken, publishableKey, stripeAccountId, promise, reactApplicationContext)
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
@ReactMethod
|
|
720
|
+
fun collectFinancialConnectionsAccounts(clientSecret: String, promise: Promise) {
|
|
721
|
+
if (!::stripe.isInitialized) {
|
|
722
|
+
promise.resolve(createMissingInitError())
|
|
723
|
+
return
|
|
724
|
+
}
|
|
725
|
+
financialConnectionsSheetFragment = FinancialConnectionsSheetFragment().also {
|
|
726
|
+
it.presentFinancialConnectionsSheet(clientSecret, FinancialConnectionsSheetFragment.Mode.ForSession, publishableKey, stripeAccountId, promise, reactApplicationContext)
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
693
730
|
/**
|
|
694
731
|
* Safely get and cast the current activity as an AppCompatActivity. If that fails, the promise
|
|
695
732
|
* provided will be resolved with an error message instructing the user to retry the method.
|
|
@@ -111,3 +111,7 @@ internal fun createError(code: String, error: Throwable): WritableMap {
|
|
|
111
111
|
null,
|
|
112
112
|
null)
|
|
113
113
|
}
|
|
114
|
+
|
|
115
|
+
internal fun createMissingInitError(): WritableMap {
|
|
116
|
+
return createError(ErrorType.Failed.toString(), "Stripe has not been initialized. Initialize Stripe in your app with the StripeProvider component or the initStripe method.")
|
|
117
|
+
}
|
|
@@ -3,6 +3,9 @@ package com.reactnativestripesdk.utils
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.view.View
|
|
5
5
|
import android.view.inputmethod.InputMethodManager
|
|
6
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
7
|
+
import androidx.fragment.app.Fragment
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
9
|
|
|
7
10
|
fun View.showSoftKeyboard() {
|
|
8
11
|
post {
|
|
@@ -19,3 +22,11 @@ fun View.hideSoftKeyboard() {
|
|
|
19
22
|
imm?.hideSoftInputFromWindow(windowToken, 0)
|
|
20
23
|
}
|
|
21
24
|
}
|
|
25
|
+
|
|
26
|
+
fun Fragment.removeFragment(context: ReactApplicationContext) {
|
|
27
|
+
(context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.let {
|
|
28
|
+
if (it.findFragmentByTag(this.tag) != null) {
|
|
29
|
+
it.beginTransaction().remove(this).commitAllowingStateLoss()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -217,12 +217,11 @@ internal fun mapFromBankAccountStatus(status: BankAccount.Status?): String {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
internal fun mapFromBankAccount(bankAccount: BankAccount?): WritableMap? {
|
|
220
|
-
val bankAccountMap: WritableMap = WritableNativeMap()
|
|
221
|
-
|
|
222
220
|
if (bankAccount == null) {
|
|
223
221
|
return null
|
|
224
222
|
}
|
|
225
223
|
|
|
224
|
+
val bankAccountMap: WritableMap = WritableNativeMap()
|
|
226
225
|
bankAccountMap.putString("id", bankAccount.id)
|
|
227
226
|
bankAccountMap.putString("bankName", bankAccount.bankName)
|
|
228
227
|
bankAccountMap.putString("accountHolderName", bankAccount.accountHolderName)
|
|
@@ -231,6 +230,8 @@ internal fun mapFromBankAccount(bankAccount: BankAccount?): WritableMap? {
|
|
|
231
230
|
bankAccountMap.putString("country", bankAccount.countryCode)
|
|
232
231
|
bankAccountMap.putString("routingNumber", bankAccount.routingNumber)
|
|
233
232
|
bankAccountMap.putString("status", mapFromBankAccountStatus(bankAccount.status))
|
|
233
|
+
bankAccountMap.putString("fingerprint", bankAccount.fingerprint)
|
|
234
|
+
bankAccountMap.putString("last4", bankAccount.last4)
|
|
234
235
|
|
|
235
236
|
return bankAccountMap
|
|
236
237
|
}
|
|
@@ -312,13 +313,13 @@ internal fun mapFromCard(card: Card?): WritableMap? {
|
|
|
312
313
|
|
|
313
314
|
internal fun mapFromToken(token: Token): WritableMap {
|
|
314
315
|
val tokenMap: WritableMap = WritableNativeMap()
|
|
315
|
-
|
|
316
316
|
tokenMap.putString("id", token.id)
|
|
317
|
-
tokenMap.
|
|
317
|
+
tokenMap.putDouble("created", token.created.time.toDouble())
|
|
318
318
|
tokenMap.putString("type", mapTokenType(token.type))
|
|
319
319
|
tokenMap.putBoolean("livemode", token.livemode)
|
|
320
320
|
tokenMap.putMap("bankAccount", mapFromBankAccount(token.bankAccount))
|
|
321
321
|
tokenMap.putMap("card", mapFromCard(token.card))
|
|
322
|
+
tokenMap.putBoolean("used", token.used)
|
|
322
323
|
|
|
323
324
|
return tokenMap
|
|
324
325
|
}
|
package/ios/Errors.swift
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Stripe
|
|
2
|
+
@_spi(STP) import StripeCore
|
|
2
3
|
|
|
3
4
|
enum ErrorType {
|
|
4
5
|
static let Failed = "Failed"
|
|
@@ -50,7 +51,7 @@ class Errors {
|
|
|
50
51
|
class func createError (_ code: String, _ error: NSError?) -> NSDictionary {
|
|
51
52
|
let value: NSDictionary = [
|
|
52
53
|
"code": code,
|
|
53
|
-
"message": error?.userInfo[STPError.errorMessageKey] ?? NSNull(),
|
|
54
|
+
"message": error?.userInfo[STPError.errorMessageKey] ?? error?.localizedDescription ?? NSNull(),
|
|
54
55
|
"localizedMessage": error?.localizedDescription ?? NSNull(),
|
|
55
56
|
"declineCode": error?.userInfo[STPError.stripeDeclineCodeKey] ?? NSNull(),
|
|
56
57
|
"stripeErrorCode": error?.userInfo[STPError.stripeErrorCodeKey] ?? NSNull(),
|
|
@@ -84,5 +85,15 @@ class Errors {
|
|
|
84
85
|
|
|
85
86
|
return ["error": value]
|
|
86
87
|
}
|
|
88
|
+
|
|
89
|
+
class func createError(_ code: String, _ error: Error) -> NSDictionary {
|
|
90
|
+
if let stripeError = error as? StripeError {
|
|
91
|
+
return createError(code, NSError.stp_error(from: stripeError))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return createError(code, error as NSError)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static let MISSING_INIT_ERROR = Errors.createError(ErrorType.Failed, "Stripe has not been initialized. Initialize Stripe in your app with the StripeProvider component or the initStripe method.")
|
|
87
98
|
}
|
|
88
99
|
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FinancialConnections.swift
|
|
3
|
+
// stripe-react-native
|
|
4
|
+
//
|
|
5
|
+
// Created by Charles Cruzan on 7/12/22.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import StripeFinancialConnections
|
|
10
|
+
import Stripe
|
|
11
|
+
|
|
12
|
+
class FinancialConnections {
|
|
13
|
+
|
|
14
|
+
internal static func present(
|
|
15
|
+
withClientSecret: String,
|
|
16
|
+
resolve: @escaping RCTPromiseResolveBlock
|
|
17
|
+
) -> Void {
|
|
18
|
+
DispatchQueue.main.async {
|
|
19
|
+
FinancialConnectionsSheet(financialConnectionsSessionClientSecret: withClientSecret).present(
|
|
20
|
+
from: findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController()),
|
|
21
|
+
completion: { result in
|
|
22
|
+
switch result {
|
|
23
|
+
case .completed(session: let session):
|
|
24
|
+
resolve([ "session": mapFromSessionResult(session) ])
|
|
25
|
+
case .canceled:
|
|
26
|
+
resolve(Errors.createError(ErrorType.Canceled, "The flow has been canceled."))
|
|
27
|
+
case .failed(let error):
|
|
28
|
+
resolve(Errors.createError(ErrorType.Failed, error))
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
internal static func presentForToken(
|
|
35
|
+
withClientSecret: String,
|
|
36
|
+
resolve: @escaping RCTPromiseResolveBlock
|
|
37
|
+
) -> Void {
|
|
38
|
+
DispatchQueue.main.async {
|
|
39
|
+
FinancialConnectionsSheet(financialConnectionsSessionClientSecret: withClientSecret).presentForToken(
|
|
40
|
+
from: findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController()),
|
|
41
|
+
completion: { result in
|
|
42
|
+
switch result {
|
|
43
|
+
case .completed(result: let result):
|
|
44
|
+
resolve(
|
|
45
|
+
[
|
|
46
|
+
"session": mapFromSessionResult(result.session),
|
|
47
|
+
"token" : mapFromTokenResult(result.token)
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
case .canceled:
|
|
51
|
+
resolve(Errors.createError(ErrorType.Canceled, "The flow has been canceled."))
|
|
52
|
+
case .failed(let error):
|
|
53
|
+
resolve(Errors.createError(ErrorType.Failed, error))
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
internal static func mapFromSessionResult(
|
|
60
|
+
_ session: StripeAPI.FinancialConnectionsSession
|
|
61
|
+
) -> NSDictionary {
|
|
62
|
+
return [
|
|
63
|
+
"id": session.id,
|
|
64
|
+
"clientSecret": session.clientSecret,
|
|
65
|
+
"livemode": session.livemode,
|
|
66
|
+
"accounts": mapFromAccountsList(accounts: session.accounts)
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
internal static func mapFromTokenResult(
|
|
71
|
+
_ token: StripeAPI.BankAccountToken?
|
|
72
|
+
) -> NSDictionary {
|
|
73
|
+
return [
|
|
74
|
+
"bankAccount": mapFromBankAccount(bankAccount: token?.bankAccount) ?? NSNull(),
|
|
75
|
+
"livemode": token?.livemode ?? false,
|
|
76
|
+
"id": token?.id ?? NSNull(),
|
|
77
|
+
"used": token?.used ?? false,
|
|
78
|
+
"type": Mappers.mapFromTokenType(STPTokenType.bankAccount) ?? NSNull(),
|
|
79
|
+
"created": NSNull(), // Doesn't exist on StripeAPI.BankAccountToken
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
internal static func mapFromBankAccount(
|
|
84
|
+
bankAccount: StripeAPI.BankAccountToken.BankAccount?
|
|
85
|
+
) -> NSDictionary? {
|
|
86
|
+
guard let bankAccount = bankAccount else {
|
|
87
|
+
return nil
|
|
88
|
+
}
|
|
89
|
+
// return Mappers.mapFromBankAccount(bankAccount) Cannot use this since it expects an STPBankAccount
|
|
90
|
+
return [
|
|
91
|
+
"id": bankAccount.id,
|
|
92
|
+
"bankName": bankAccount.bankName ?? NSNull(),
|
|
93
|
+
"accountHolderName": bankAccount.accountHolderName ?? NSNull(),
|
|
94
|
+
"accountHolderType": NSNull(), // Doesn't exist on StripeAPI.BankAccountToken
|
|
95
|
+
"currency": bankAccount.currency,
|
|
96
|
+
"country": bankAccount.country,
|
|
97
|
+
"routingNumber": bankAccount.routingNumber ?? NSNull(),
|
|
98
|
+
"fingerprint": bankAccount.fingerprint ?? NSNull(),
|
|
99
|
+
"last4": bankAccount.last4,
|
|
100
|
+
"status": bankAccount.status.prefix(1).uppercased() + bankAccount.status.lowercased().dropFirst(), // stripe-ios returns a string, not STPBankAccountStatus
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
internal static func mapFromAccountsList(
|
|
105
|
+
accounts: StripeAPI.FinancialConnectionsSession.AccountList
|
|
106
|
+
) -> [[String: Any]] {
|
|
107
|
+
var result = [[String: Any]]()
|
|
108
|
+
|
|
109
|
+
for account in accounts.data {
|
|
110
|
+
result.append([
|
|
111
|
+
"id": account.id,
|
|
112
|
+
"livemode": account.livemode,
|
|
113
|
+
"displayName": account.displayName ?? NSNull(),
|
|
114
|
+
"status": mapFromStatus(account.status),
|
|
115
|
+
"institutionName": account.institutionName,
|
|
116
|
+
"last4": account.last4 ?? NSNull(),
|
|
117
|
+
"created": account.created * 1000,
|
|
118
|
+
"balance": mapFromAccountBalance(balance: account.balance) ?? NSNull(),
|
|
119
|
+
"balanceRefresh": mapFromAccountBalanceRefresh(balanceRefresh: account.balanceRefresh) ?? NSNull(),
|
|
120
|
+
"category": mapFromCategory(account.category),
|
|
121
|
+
"subcategory": mapFromSubcategory(account.subcategory),
|
|
122
|
+
"permissions": account.permissions?.map { mapFromPermission($0) } ?? NSNull(),
|
|
123
|
+
"supportedPaymentMethodTypes": account.supportedPaymentMethodTypes.map { mapFromSupportedPaymentMethodTypes($0) },
|
|
124
|
+
])
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
internal static func mapFromAccountBalance(
|
|
131
|
+
balance: StripeAPI.FinancialConnectionsAccount.Balance?
|
|
132
|
+
) -> NSDictionary? {
|
|
133
|
+
guard let balance = balance else {
|
|
134
|
+
return nil
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return [
|
|
138
|
+
"asOf": balance.asOf * 1000,
|
|
139
|
+
"type": mapFromBalanceType(balance.type),
|
|
140
|
+
// TODO: Protected by internal on iOS only. PR is out to fix
|
|
141
|
+
"cash": ["available": NSNull()], // balance.cash?.available
|
|
142
|
+
"credit": ["used": NSNull()], // balance.credit?.used
|
|
143
|
+
"current": balance.current,
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
internal static func mapFromAccountBalanceRefresh(
|
|
148
|
+
balanceRefresh: StripeAPI.FinancialConnectionsAccount.BalanceRefresh?
|
|
149
|
+
) -> NSDictionary? {
|
|
150
|
+
guard let balanceRefresh = balanceRefresh else {
|
|
151
|
+
return nil
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return [
|
|
155
|
+
"status": mapFromBalanceRefreshStatus(balanceRefresh.status),
|
|
156
|
+
"lastAttemptedAt": balanceRefresh.lastAttemptedAt * 1000,
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
internal static func mapFromStatus( _ status: StripeAPI.FinancialConnectionsAccount.Status) -> String {
|
|
161
|
+
switch status {
|
|
162
|
+
case .active:
|
|
163
|
+
return "active"
|
|
164
|
+
case .inactive:
|
|
165
|
+
return "inactive"
|
|
166
|
+
case .disconnected:
|
|
167
|
+
return "disconnected"
|
|
168
|
+
case .unparsable:
|
|
169
|
+
return "unparsable"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
internal static func mapFromCategory( _ category: StripeAPI.FinancialConnectionsAccount.Category) -> String {
|
|
174
|
+
switch category {
|
|
175
|
+
case .cash:
|
|
176
|
+
return "cash"
|
|
177
|
+
case .credit:
|
|
178
|
+
return "credit"
|
|
179
|
+
case .investment:
|
|
180
|
+
return "investment"
|
|
181
|
+
case .other:
|
|
182
|
+
return "other"
|
|
183
|
+
case .unparsable:
|
|
184
|
+
return "unparsable"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
internal static func mapFromSubcategory( _ subcategory: StripeAPI.FinancialConnectionsAccount.Subcategory) -> String {
|
|
189
|
+
switch subcategory {
|
|
190
|
+
case .savings:
|
|
191
|
+
return "savings"
|
|
192
|
+
case .mortgage:
|
|
193
|
+
return "mortgage"
|
|
194
|
+
case .checking:
|
|
195
|
+
return "checking"
|
|
196
|
+
case .creditCard:
|
|
197
|
+
return "creditCard"
|
|
198
|
+
case .lineOfCredit:
|
|
199
|
+
return "lineOfCredit"
|
|
200
|
+
case .other:
|
|
201
|
+
return "other"
|
|
202
|
+
case .unparsable:
|
|
203
|
+
return "unparsable"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
internal static func mapFromPermission( _ permission: StripeAPI.FinancialConnectionsAccount.Permissions) -> String {
|
|
208
|
+
switch permission {
|
|
209
|
+
case .transactions:
|
|
210
|
+
return "transactions"
|
|
211
|
+
case .ownership:
|
|
212
|
+
return "ownership"
|
|
213
|
+
case .paymentMethod:
|
|
214
|
+
return "paymentMethod"
|
|
215
|
+
case .accountNumbers:
|
|
216
|
+
return "accountNumbers"
|
|
217
|
+
case .balances:
|
|
218
|
+
return "balances"
|
|
219
|
+
case .unparsable:
|
|
220
|
+
return "unparsable"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
internal static func mapFromSupportedPaymentMethodTypes( _ type: StripeAPI.FinancialConnectionsAccount.SupportedPaymentMethodTypes) -> String {
|
|
225
|
+
switch type {
|
|
226
|
+
case .usBankAccount:
|
|
227
|
+
return "usBankAccount"
|
|
228
|
+
case .link:
|
|
229
|
+
return "link"
|
|
230
|
+
case .unparsable:
|
|
231
|
+
return "unparsable"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
internal static func mapFromBalanceType( _ type: StripeAPI.FinancialConnectionsAccount.Balance.ModelType) -> String {
|
|
236
|
+
switch type {
|
|
237
|
+
case .cash:
|
|
238
|
+
return "cash"
|
|
239
|
+
case .credit:
|
|
240
|
+
return "credit"
|
|
241
|
+
case .unparsable:
|
|
242
|
+
return "unparsable"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
internal static func mapFromBalanceRefreshStatus( _ status: StripeAPI.FinancialConnectionsAccount.BalanceRefresh.Status) -> String {
|
|
247
|
+
switch status {
|
|
248
|
+
case .succeeded:
|
|
249
|
+
return "succeeded"
|
|
250
|
+
case .pending:
|
|
251
|
+
return "pending"
|
|
252
|
+
case .failed:
|
|
253
|
+
return "failed"
|
|
254
|
+
case .unparsable:
|
|
255
|
+
return "unparsable"
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
package/ios/Mappers.swift
CHANGED
|
@@ -50,18 +50,21 @@ class Mappers {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
class func mapFromBankAccount(_ bankAccount: STPBankAccount?) -> NSDictionary? {
|
|
53
|
-
|
|
53
|
+
guard let bankAccount = bankAccount else {
|
|
54
54
|
return nil
|
|
55
55
|
}
|
|
56
|
+
|
|
56
57
|
let result: NSDictionary = [
|
|
57
|
-
"id": bankAccount
|
|
58
|
-
"bankName": bankAccount
|
|
59
|
-
"accountHolderName": bankAccount
|
|
60
|
-
"accountHolderType": mapFromBankAccountHolderType(bankAccount
|
|
61
|
-
"country": bankAccount
|
|
62
|
-
"currency": bankAccount
|
|
63
|
-
"routingNumber": bankAccount
|
|
64
|
-
"status": mapFromBankAccountStatus(bankAccount
|
|
58
|
+
"id": bankAccount.stripeID,
|
|
59
|
+
"bankName": bankAccount.bankName ?? NSNull(),
|
|
60
|
+
"accountHolderName": bankAccount.accountHolderName ?? NSNull(),
|
|
61
|
+
"accountHolderType": mapFromBankAccountHolderType(bankAccount.accountHolderType) ?? NSNull(),
|
|
62
|
+
"country": bankAccount.country ?? NSNull(),
|
|
63
|
+
"currency": bankAccount.currency ?? NSNull(),
|
|
64
|
+
"routingNumber": bankAccount.routingNumber ?? NSNull(),
|
|
65
|
+
"status": mapFromBankAccountStatus(bankAccount.status) ?? NSNull(),
|
|
66
|
+
"fingerprint": bankAccount.fingerprint ?? NSNull(),
|
|
67
|
+
"last4": bankAccount.last4 ?? NSNull()
|
|
65
68
|
]
|
|
66
69
|
return result
|
|
67
70
|
}
|
package/ios/StripeSdk.m
CHANGED
|
@@ -131,5 +131,14 @@ RCT_EXTERN_METHOD(
|
|
|
131
131
|
resolver: (RCTPromiseResolveBlock)resolve
|
|
132
132
|
rejecter: (RCTPromiseRejectBlock)reject
|
|
133
133
|
)
|
|
134
|
-
|
|
134
|
+
RCT_EXTERN_METHOD(
|
|
135
|
+
collectBankAccountToken:(NSString *)clientSecret
|
|
136
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
137
|
+
rejecter: (RCTPromiseRejectBlock)reject
|
|
138
|
+
)
|
|
139
|
+
RCT_EXTERN_METHOD(
|
|
140
|
+
collectFinancialConnectionsAccounts:(NSString *)clientSecret
|
|
141
|
+
resolver: (RCTPromiseResolveBlock)resolve
|
|
142
|
+
rejecter: (RCTPromiseRejectBlock)reject
|
|
143
|
+
)
|
|
135
144
|
@end
|
package/ios/StripeSdk.swift
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PassKit
|
|
2
2
|
import Stripe
|
|
3
|
+
import StripeFinancialConnections
|
|
3
4
|
|
|
4
5
|
@objc(StripeSdk)
|
|
5
6
|
class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionViewControllerDelegate, UIAdaptivePresentationControllerDelegate {
|
|
@@ -800,7 +801,7 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
|
|
|
800
801
|
@objc(confirmPayment:data:options:resolver:rejecter:)
|
|
801
802
|
func confirmPayment(
|
|
802
803
|
paymentIntentClientSecret: String,
|
|
803
|
-
params: NSDictionary
|
|
804
|
+
params: NSDictionary?,
|
|
804
805
|
options: NSDictionary,
|
|
805
806
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
806
807
|
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
@@ -808,13 +809,13 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
|
|
|
808
809
|
self.confirmPaymentResolver = resolve
|
|
809
810
|
self.confirmPaymentClientSecret = paymentIntentClientSecret
|
|
810
811
|
|
|
811
|
-
let paymentMethodData = params["paymentMethodData"] as? NSDictionary
|
|
812
|
-
let
|
|
813
|
-
|
|
814
|
-
resolve(
|
|
812
|
+
let paymentMethodData = params?["paymentMethodData"] as? NSDictionary
|
|
813
|
+
let (missingPaymentMethodError, paymentMethodType) = getPaymentMethodType(params: params)
|
|
814
|
+
if (missingPaymentMethodError != nil) {
|
|
815
|
+
resolve(missingPaymentMethodError)
|
|
815
816
|
return
|
|
816
817
|
}
|
|
817
|
-
|
|
818
|
+
|
|
818
819
|
if (paymentMethodType == .FPX) {
|
|
819
820
|
let testOfflineBank = paymentMethodData?["testOfflineBank"] as? Bool
|
|
820
821
|
if (testOfflineBank == false || testOfflineBank == nil) {
|
|
@@ -831,10 +832,24 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
|
|
|
831
832
|
STPPaymentHandler.shared().confirmPayment(paymentIntentParams, with: self, completion: onCompleteConfirmPayment)
|
|
832
833
|
}
|
|
833
834
|
}
|
|
835
|
+
|
|
836
|
+
func getPaymentMethodType(
|
|
837
|
+
params: NSDictionary?
|
|
838
|
+
) -> (NSDictionary?, STPPaymentMethodType?) {
|
|
839
|
+
if let params = params {
|
|
840
|
+
guard let paymentMethodType = Mappers.mapToPaymentMethodType(type: params["paymentMethodType"] as? String) else {
|
|
841
|
+
return (Errors.createError(ErrorType.Failed, "You must provide paymentMethodType"), nil)
|
|
842
|
+
}
|
|
843
|
+
return (nil, paymentMethodType)
|
|
844
|
+
} else {
|
|
845
|
+
// If params aren't provided, it means we expect that the payment method was attached on the server side
|
|
846
|
+
return (nil, nil)
|
|
847
|
+
}
|
|
848
|
+
}
|
|
834
849
|
|
|
835
850
|
func createPaymentIntentParams(
|
|
836
851
|
paymentIntentClientSecret: String,
|
|
837
|
-
paymentMethodType: STPPaymentMethodType
|
|
852
|
+
paymentMethodType: STPPaymentMethodType?,
|
|
838
853
|
paymentMethodData: NSDictionary?,
|
|
839
854
|
options: NSDictionary
|
|
840
855
|
) -> (NSDictionary?, STPPaymentIntentParams) {
|
|
@@ -846,6 +861,8 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
|
|
|
846
861
|
if (paymentMethodType == .USBankAccount && paymentMethodData == nil) {
|
|
847
862
|
return STPPaymentIntentParams(clientSecret: paymentIntentClientSecret, paymentMethodType: .USBankAccount)
|
|
848
863
|
} else {
|
|
864
|
+
guard let paymentMethodType = paymentMethodType else { return STPPaymentIntentParams(clientSecret: paymentIntentClientSecret) }
|
|
865
|
+
|
|
849
866
|
let paymentMethodId = paymentMethodData?["paymentMethodId"] as? String
|
|
850
867
|
let parameters = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret)
|
|
851
868
|
|
|
@@ -1023,7 +1040,33 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
|
|
|
1023
1040
|
}
|
|
1024
1041
|
resolve(["isInWallet": PushProvisioningUtils.passExistsWith(last4: last4)])
|
|
1025
1042
|
}
|
|
1026
|
-
|
|
1043
|
+
|
|
1044
|
+
@objc(collectBankAccountToken:resolver:rejecter:)
|
|
1045
|
+
func collectBankAccountToken(
|
|
1046
|
+
clientSecret: String,
|
|
1047
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
1048
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
1049
|
+
) -> Void {
|
|
1050
|
+
if (STPAPIClient.shared.publishableKey == nil) {
|
|
1051
|
+
resolve(Errors.MISSING_INIT_ERROR)
|
|
1052
|
+
return
|
|
1053
|
+
}
|
|
1054
|
+
FinancialConnections.presentForToken(withClientSecret: clientSecret, resolve: resolve)
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
@objc(collectFinancialConnectionsAccounts:resolver:rejecter:)
|
|
1058
|
+
func collectFinancialConnectionsAccounts(
|
|
1059
|
+
clientSecret: String,
|
|
1060
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
1061
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
1062
|
+
) -> Void {
|
|
1063
|
+
if (STPAPIClient.shared.publishableKey == nil) {
|
|
1064
|
+
resolve(Errors.MISSING_INIT_ERROR)
|
|
1065
|
+
return
|
|
1066
|
+
}
|
|
1067
|
+
FinancialConnections.present(withClientSecret: clientSecret, resolve: resolve)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1027
1070
|
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
1028
1071
|
confirmPaymentResolver?(Errors.createError(ErrorType.Canceled, "FPX Payment has been canceled"))
|
|
1029
1072
|
}
|