@stripe/stripe-react-native 0.20.0 → 0.21.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/CHANGELOG.md +13 -0
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/reactnativestripesdk/CollectBankAccountLauncherFragment.kt +1 -1
- package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetFragment.kt +4 -1
- package/android/src/main/java/com/reactnativestripesdk/GooglePayFragment.kt +1 -1
- package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +1 -1
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +10 -9
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +8 -3
- package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +20 -14
- package/android/src/main/java/com/reactnativestripesdk/StripeSdkPackage.kt +3 -1
- package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherFragment.kt +111 -0
- package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetEvent.kt +28 -0
- package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetView.kt +178 -0
- package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetViewManager.kt +67 -0
- package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +1 -1
- package/ios/AddressSheet/AddressSheetUtils.swift +98 -0
- package/ios/AddressSheet/AddressSheetView.swift +131 -0
- package/ios/AddressSheet/AddressSheetViewManager.m +25 -0
- package/ios/AddressSheet/AddressSheetViewManager.swift +19 -0
- package/ios/PaymentSheetAppearance.swift +24 -23
- package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonManager.m +0 -0
- package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonManager.swift +0 -0
- package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonView.swift +0 -0
- package/ios/{pushprovisioning → PushProvisioning}/PushProvisioningUtils.swift +0 -0
- package/ios/StripeSdk.swift +7 -1
- package/ios/Tests/AddressSheetUtilsTests.swift +279 -0
- package/lib/commonjs/components/AddressSheet.js +2 -0
- package/lib/commonjs/components/AddressSheet.js.map +1 -0
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types/Errors.js +1 -1
- package/lib/commonjs/types/Errors.js.map +1 -1
- package/lib/commonjs/types/index.js +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/module/components/AddressSheet.js +2 -0
- package/lib/module/components/AddressSheet.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/Errors.js +1 -1
- package/lib/module/types/Errors.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/components/AddressSheet.d.ts +53 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/types/Common.d.ts +12 -0
- package/lib/typescript/src/types/Errors.d.ts +4 -0
- package/lib/typescript/src/types/PaymentSheet.d.ts +7 -1
- package/lib/typescript/src/types/index.d.ts +3 -6
- package/package.json +1 -1
- package/src/components/AddressSheet.tsx +82 -0
- package/src/index.tsx +4 -1
- package/src/types/Common.ts +13 -0
- package/src/types/Errors.ts +5 -0
- package/src/types/PaymentSheet.ts +7 -1
- package/src/types/index.ts +5 -10
- package/stripe-react-native.podspec +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.21.0 - 2022-11-15
|
|
6
|
+
|
|
7
|
+
### Breaking changes
|
|
8
|
+
|
|
9
|
+
### New features
|
|
10
|
+
|
|
11
|
+
- Added the `<AddressSheet />` component, which enables you to collect local and international shipping or billing addresses from your customers _with_ address autocomplete. [#1169](https://github.com/stripe/stripe-react-native/pull/1169)
|
|
12
|
+
- Added the `defaultShippingDetails` field to the `params` argument in `initPaymentSheet(params)`. This will allow you to collect shipping details (either in your own UI or using the new `<AddressSheet />` component) for payments in the Payment Sheet. [#1169](https://github.com/stripe/stripe-react-native/pull/1169)
|
|
13
|
+
|
|
14
|
+
## Fixes
|
|
15
|
+
|
|
16
|
+
- Fixed a build error on Android when using Kotlin version 1.7.10. [#1195](https://github.com/stripe/stripe-react-native/pull/1195)
|
|
17
|
+
|
|
5
18
|
## 0.20.0 - 2022-11-03
|
|
6
19
|
|
|
7
20
|
### Breaking changes
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
StripeSdk_kotlinVersion=1.6.21
|
|
2
|
-
StripeSdk_stripeVersion=20.
|
|
2
|
+
StripeSdk_stripeVersion=20.16.+
|
|
@@ -125,7 +125,7 @@ class FinancialConnectionsSheetFragment : Fragment() {
|
|
|
125
125
|
private fun commitFragmentAndStartFlow(currentActivity: AppCompatActivity) {
|
|
126
126
|
try {
|
|
127
127
|
currentActivity.supportFragmentManager.beginTransaction()
|
|
128
|
-
.add(this,
|
|
128
|
+
.add(this, TAG)
|
|
129
129
|
.commit()
|
|
130
130
|
} catch (error: IllegalStateException) {
|
|
131
131
|
promise.resolve(createError(ErrorType.Failed.toString(), error.message))
|
|
@@ -133,6 +133,8 @@ class FinancialConnectionsSheetFragment : Fragment() {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
companion object {
|
|
136
|
+
internal const val TAG = "financial_connections_sheet_launch_fragment"
|
|
137
|
+
|
|
136
138
|
private fun createTokenResult(result: FinancialConnectionsSheetForTokenResult.Completed): WritableMap {
|
|
137
139
|
return WritableNativeMap().also {
|
|
138
140
|
it.putMap("session", mapFromSession(result.financialConnectionsSession))
|
|
@@ -239,6 +241,7 @@ class FinancialConnectionsSheetFragment : Fragment() {
|
|
|
239
241
|
FinancialConnectionsAccount.Permissions.TRANSACTIONS -> "transactions"
|
|
240
242
|
FinancialConnectionsAccount.Permissions.ACCOUNT_NUMBERS -> "accountNumbers"
|
|
241
243
|
FinancialConnectionsAccount.Permissions.UNKNOWN -> "unparsable"
|
|
244
|
+
FinancialConnectionsAccount.Permissions.ACCOUNT_NUMBERS -> "accountNumbers"
|
|
242
245
|
}
|
|
243
246
|
}
|
|
244
247
|
|
|
@@ -2,27 +2,28 @@ package com.reactnativestripesdk
|
|
|
2
2
|
|
|
3
3
|
import android.graphics.Color
|
|
4
4
|
import android.os.Bundle
|
|
5
|
+
import com.facebook.react.bridge.ReactContext
|
|
5
6
|
import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
|
|
6
7
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
7
8
|
|
|
8
|
-
fun
|
|
9
|
+
fun buildPaymentSheetAppearance(userParams: Bundle?, context: ReactContext): PaymentSheet.Appearance {
|
|
9
10
|
val colorParams = userParams?.getBundle(PaymentSheetAppearanceKeys.COLORS)
|
|
10
11
|
val lightColorParams = colorParams?.getBundle(PaymentSheetAppearanceKeys.LIGHT) ?: colorParams
|
|
11
12
|
val darkColorParams = colorParams?.getBundle(PaymentSheetAppearanceKeys.DARK) ?: colorParams
|
|
12
13
|
|
|
13
14
|
return PaymentSheet.Appearance(
|
|
14
|
-
typography = buildTypography(userParams?.getBundle(PaymentSheetAppearanceKeys.FONT)),
|
|
15
|
+
typography = buildTypography(userParams?.getBundle(PaymentSheetAppearanceKeys.FONT), context),
|
|
15
16
|
colorsLight = buildColors(lightColorParams, PaymentSheet.Colors.defaultLight),
|
|
16
17
|
colorsDark = buildColors(darkColorParams, PaymentSheet.Colors.defaultDark),
|
|
17
18
|
shapes = buildShapes(userParams?.getBundle(PaymentSheetAppearanceKeys.SHAPES)),
|
|
18
|
-
primaryButton = buildPrimaryButton(userParams?.getBundle(PaymentSheetAppearanceKeys.PRIMARY_BUTTON))
|
|
19
|
+
primaryButton = buildPrimaryButton(userParams?.getBundle(PaymentSheetAppearanceKeys.PRIMARY_BUTTON), context)
|
|
19
20
|
)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
private fun
|
|
23
|
+
private fun buildTypography(fontParams: Bundle?, context: ReactContext): PaymentSheet.Typography {
|
|
23
24
|
return PaymentSheet.Typography.default.copy(
|
|
24
25
|
sizeScaleFactor = getFloatOr(fontParams, PaymentSheetAppearanceKeys.SCALE, PaymentSheet.Typography.default.sizeScaleFactor),
|
|
25
|
-
fontResId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, PaymentSheet.Typography.default.fontResId)
|
|
26
|
+
fontResId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, PaymentSheet.Typography.default.fontResId, context)
|
|
26
27
|
)
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -64,7 +65,7 @@ private fun buildShapes(shapeParams: Bundle?): PaymentSheet.Shapes {
|
|
|
64
65
|
)
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
private fun
|
|
68
|
+
private fun buildPrimaryButton(params: Bundle?, context: ReactContext): PaymentSheet.PrimaryButton {
|
|
68
69
|
if (params == null) {
|
|
69
70
|
return PaymentSheet.PrimaryButton()
|
|
70
71
|
}
|
|
@@ -83,7 +84,7 @@ private fun PaymentSheetFragment.buildPrimaryButton(params: Bundle?): PaymentShe
|
|
|
83
84
|
borderStrokeWidthDp = getFloatOrNull(shapeParams, PaymentSheetAppearanceKeys.BORDER_WIDTH),
|
|
84
85
|
),
|
|
85
86
|
typography = PaymentSheet.PrimaryButtonTypography(
|
|
86
|
-
fontResId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, null)
|
|
87
|
+
fontResId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, null, context)
|
|
87
88
|
)
|
|
88
89
|
)
|
|
89
90
|
}
|
|
@@ -120,7 +121,7 @@ private fun getFloatOrNull(bundle: Bundle?, key: String): Float? {
|
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
@Throws(PaymentSheetAppearanceException::class)
|
|
123
|
-
private fun
|
|
124
|
+
private fun getFontResId(bundle: Bundle?, key: String, defaultValue: Int?, context: ReactContext): Int? {
|
|
124
125
|
val fontErrorPrefix = "Encountered an error when setting a custom font:"
|
|
125
126
|
if (bundle?.containsKey(key) != true) {
|
|
126
127
|
return defaultValue
|
|
@@ -134,7 +135,7 @@ private fun PaymentSheetFragment.getFontResId(bundle: Bundle?, key: String, defa
|
|
|
134
135
|
)
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
val id = resources.getIdentifier(fontFileName, "font", context
|
|
138
|
+
val id = context.resources.getIdentifier(fontFileName, "font", context.packageName)
|
|
138
139
|
if (id == 0) {
|
|
139
140
|
throw PaymentSheetAppearanceException("$fontErrorPrefix Failed to find font: $fontFileName")
|
|
140
141
|
} else {
|
|
@@ -10,7 +10,6 @@ import android.view.LayoutInflater
|
|
|
10
10
|
import android.view.View
|
|
11
11
|
import android.view.ViewGroup
|
|
12
12
|
import android.widget.FrameLayout
|
|
13
|
-
import androidx.appcompat.app.AppCompatActivity
|
|
14
13
|
import androidx.appcompat.content.res.AppCompatResources
|
|
15
14
|
import androidx.core.graphics.drawable.DrawableCompat
|
|
16
15
|
import androidx.fragment.app.Fragment
|
|
@@ -18,6 +17,7 @@ import com.facebook.react.bridge.Promise
|
|
|
18
17
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
19
18
|
import com.facebook.react.bridge.WritableMap
|
|
20
19
|
import com.facebook.react.bridge.WritableNativeMap
|
|
20
|
+
import com.reactnativestripesdk.addresssheet.AddressSheetView
|
|
21
21
|
import com.reactnativestripesdk.utils.*
|
|
22
22
|
import com.reactnativestripesdk.utils.createError
|
|
23
23
|
import com.reactnativestripesdk.utils.createResult
|
|
@@ -65,12 +65,16 @@ class PaymentSheetFragment(
|
|
|
65
65
|
paymentIntentClientSecret = arguments?.getString("paymentIntentClientSecret").orEmpty()
|
|
66
66
|
setupIntentClientSecret = arguments?.getString("setupIntentClientSecret").orEmpty()
|
|
67
67
|
val appearance = try {
|
|
68
|
-
buildPaymentSheetAppearance(arguments?.getBundle("appearance"))
|
|
68
|
+
buildPaymentSheetAppearance(arguments?.getBundle("appearance"), context)
|
|
69
69
|
} catch (error: PaymentSheetAppearanceException) {
|
|
70
70
|
initPromise.resolve(createError(ErrorType.Failed.toString(), error))
|
|
71
71
|
return
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
val shippingDetails = arguments?.getBundle("defaultShippingDetails")?.let {
|
|
75
|
+
AddressSheetView.buildAddressDetails(it)
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
val paymentOptionCallback = PaymentOptionCallback { paymentOption ->
|
|
75
79
|
val result = paymentOption?.let {
|
|
76
80
|
val bitmap = getBitmapFromVectorDrawable(context, it.drawableResourceId)
|
|
@@ -128,6 +132,7 @@ class PaymentSheetFragment(
|
|
|
128
132
|
) else null,
|
|
129
133
|
googlePay = googlePayConfig,
|
|
130
134
|
appearance = appearance,
|
|
135
|
+
shippingDetails = shippingDetails,
|
|
131
136
|
primaryButtonLabel = primaryButtonLabel
|
|
132
137
|
)
|
|
133
138
|
|
|
@@ -198,7 +203,7 @@ class PaymentSheetFragment(
|
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
companion object {
|
|
201
|
-
const val TAG = "payment_sheet_launch_fragment"
|
|
206
|
+
internal const val TAG = "payment_sheet_launch_fragment"
|
|
202
207
|
|
|
203
208
|
internal fun buildGooglePayConfig(params: Bundle?): PaymentSheet.GooglePayConfiguration? {
|
|
204
209
|
if (params == null) {
|
|
@@ -5,13 +5,11 @@ 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
|
|
9
8
|
import com.facebook.react.bridge.*
|
|
10
9
|
import com.facebook.react.module.annotations.ReactModule
|
|
10
|
+
import com.reactnativestripesdk.addresssheet.AddressLauncherFragment
|
|
11
11
|
import com.reactnativestripesdk.pushprovisioning.PushProvisioningProxy
|
|
12
12
|
import com.reactnativestripesdk.utils.*
|
|
13
|
-
import com.reactnativestripesdk.utils.createError
|
|
14
|
-
import com.reactnativestripesdk.utils.createMissingActivityError
|
|
15
13
|
import com.stripe.android.*
|
|
16
14
|
import com.stripe.android.core.ApiVersion
|
|
17
15
|
import com.stripe.android.core.AppInfo
|
|
@@ -45,14 +43,17 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
45
43
|
private var googlePayFragment: GooglePayFragment? = null
|
|
46
44
|
private var paymentLauncherFragment: PaymentLauncherFragment? = null
|
|
47
45
|
private var collectBankAccountLauncherFragment: CollectBankAccountLauncherFragment? = null
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
|
|
47
|
+
// If you create a new Fragment, you must put the tag here, otherwise result callbacks for that
|
|
48
|
+
// Fragment will not work on RN < 0.65
|
|
49
|
+
private val allStripeFragmentTags: List<String>
|
|
50
50
|
get() = listOf(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
PaymentSheetFragment.TAG,
|
|
52
|
+
GooglePayFragment.TAG,
|
|
53
|
+
PaymentLauncherFragment.TAG,
|
|
54
|
+
CollectBankAccountLauncherFragment.TAG,
|
|
55
|
+
FinancialConnectionsSheetFragment.TAG,
|
|
56
|
+
AddressLauncherFragment.TAG
|
|
56
57
|
)
|
|
57
58
|
|
|
58
59
|
private val mActivityEventListener = object : BaseActivityEventListener() {
|
|
@@ -77,8 +78,12 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
77
78
|
|
|
78
79
|
// Necessary on older versions of React Native (~0.65 and below)
|
|
79
80
|
private fun dispatchActivityResultsToFragments(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
getCurrentActivityOrResolveWithError(null)?.supportFragmentManager?.let { fragmentManager ->
|
|
82
|
+
for (tag in allStripeFragmentTags) {
|
|
83
|
+
fragmentManager.findFragmentByTag(tag)?.let {
|
|
84
|
+
it.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
|
|
@@ -120,6 +125,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
this.publishableKey = publishableKey
|
|
128
|
+
AddressLauncherFragment.publishableKey = publishableKey
|
|
123
129
|
|
|
124
130
|
val name = getValOr(appInfo, "name", "") as String
|
|
125
131
|
val partnerId = getValOr(appInfo, "partnerId", "")
|
|
@@ -718,7 +724,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
718
724
|
promise.resolve(createMissingInitError())
|
|
719
725
|
return
|
|
720
726
|
}
|
|
721
|
-
|
|
727
|
+
FinancialConnectionsSheetFragment().also {
|
|
722
728
|
it.presentFinancialConnectionsSheet(clientSecret, FinancialConnectionsSheetFragment.Mode.ForToken, publishableKey, stripeAccountId, promise, reactApplicationContext)
|
|
723
729
|
}
|
|
724
730
|
}
|
|
@@ -729,7 +735,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
|
|
|
729
735
|
promise.resolve(createMissingInitError())
|
|
730
736
|
return
|
|
731
737
|
}
|
|
732
|
-
|
|
738
|
+
FinancialConnectionsSheetFragment().also {
|
|
733
739
|
it.presentFinancialConnectionsSheet(clientSecret, FinancialConnectionsSheetFragment.Mode.ForSession, publishableKey, stripeAccountId, promise, reactApplicationContext)
|
|
734
740
|
}
|
|
735
741
|
}
|
|
@@ -4,6 +4,7 @@ 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
|
+
import com.reactnativestripesdk.addresssheet.AddressSheetViewManager
|
|
7
8
|
import com.reactnativestripesdk.pushprovisioning.AddToWalletButtonManager
|
|
8
9
|
|
|
9
10
|
class StripeSdkPackage : ReactPackage {
|
|
@@ -18,7 +19,8 @@ class StripeSdkPackage : ReactPackage {
|
|
|
18
19
|
StripeContainerManager(),
|
|
19
20
|
CardFormViewManager(),
|
|
20
21
|
GooglePayButtonManager(),
|
|
21
|
-
AddToWalletButtonManager(reactContext)
|
|
22
|
+
AddToWalletButtonManager(reactContext),
|
|
23
|
+
AddressSheetViewManager()
|
|
22
24
|
)
|
|
23
25
|
}
|
|
24
26
|
}
|
package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherFragment.kt
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
package com.reactnativestripesdk.addresssheet
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.view.LayoutInflater
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import android.widget.FrameLayout
|
|
8
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
9
|
+
import androidx.fragment.app.Fragment
|
|
10
|
+
import com.facebook.react.bridge.ReactContext
|
|
11
|
+
import com.facebook.react.bridge.WritableMap
|
|
12
|
+
import com.reactnativestripesdk.utils.ErrorType
|
|
13
|
+
import com.reactnativestripesdk.utils.createError
|
|
14
|
+
import com.stripe.android.paymentsheet.PaymentSheet
|
|
15
|
+
import com.stripe.android.paymentsheet.addresselement.AddressDetails
|
|
16
|
+
import com.stripe.android.paymentsheet.addresselement.AddressLauncher
|
|
17
|
+
import com.stripe.android.paymentsheet.addresselement.AddressLauncherResult
|
|
18
|
+
|
|
19
|
+
class AddressLauncherFragment : Fragment() {
|
|
20
|
+
companion object {
|
|
21
|
+
internal var publishableKey: String? = null
|
|
22
|
+
internal const val TAG = "address_launcher_fragment"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private lateinit var addressLauncher: AddressLauncher
|
|
26
|
+
private var configuration = AddressLauncher.Configuration()
|
|
27
|
+
private var callback: ((error: WritableMap?, address: AddressDetails?) -> Unit)? = null
|
|
28
|
+
|
|
29
|
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
|
30
|
+
savedInstanceState: Bundle?): View {
|
|
31
|
+
return FrameLayout(requireActivity()).also {
|
|
32
|
+
it.visibility = View.GONE
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
37
|
+
publishableKey?.let { publishableKey ->
|
|
38
|
+
addressLauncher = AddressLauncher(this,
|
|
39
|
+
::onAddressLauncherResult).also {
|
|
40
|
+
it.present(
|
|
41
|
+
publishableKey = publishableKey,
|
|
42
|
+
configuration = configuration
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
} ?: run {
|
|
46
|
+
callback?.invoke(
|
|
47
|
+
createError(ErrorType.Failed.toString(), "No publishable key set. Stripe has not been initialized. Initialize Stripe in your app with the StripeProvider component or the initStripe method."),
|
|
48
|
+
null
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private fun onAddressLauncherResult(result: AddressLauncherResult) {
|
|
54
|
+
when (result) {
|
|
55
|
+
is AddressLauncherResult.Canceled -> {
|
|
56
|
+
callback?.invoke(
|
|
57
|
+
createError(ErrorType.Canceled.toString(), "The flow has been canceled."),
|
|
58
|
+
null
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
is AddressLauncherResult.Succeeded -> {
|
|
62
|
+
callback?.invoke(
|
|
63
|
+
null,
|
|
64
|
+
result.address
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fun presentAddressSheet(
|
|
71
|
+
context: ReactContext,
|
|
72
|
+
appearance: PaymentSheet.Appearance,
|
|
73
|
+
defaultAddress: AddressDetails?,
|
|
74
|
+
allowedCountries: Set<String>,
|
|
75
|
+
buttonTitle: String?,
|
|
76
|
+
title: String?,
|
|
77
|
+
googlePlacesApiKey: String?,
|
|
78
|
+
autocompleteCountries: Set<String>,
|
|
79
|
+
additionalFields: AddressLauncher.AdditionalFieldsConfiguration?,
|
|
80
|
+
callback: ((error: WritableMap?, address: AddressDetails?) -> Unit)) {
|
|
81
|
+
configuration = AddressLauncher.Configuration(
|
|
82
|
+
appearance = appearance,
|
|
83
|
+
address = defaultAddress,
|
|
84
|
+
allowedCountries = allowedCountries,
|
|
85
|
+
buttonTitle = buttonTitle,
|
|
86
|
+
additionalFields = additionalFields,
|
|
87
|
+
title = title,
|
|
88
|
+
googlePlacesApiKey = googlePlacesApiKey,
|
|
89
|
+
autocompleteCountries = autocompleteCountries,
|
|
90
|
+
)
|
|
91
|
+
this.callback = callback
|
|
92
|
+
(context.currentActivity as? AppCompatActivity)?.let {
|
|
93
|
+
attemptToCleanupPreviousFragment(it)
|
|
94
|
+
commitFragmentAndStartFlow(it)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private fun attemptToCleanupPreviousFragment(currentActivity: AppCompatActivity) {
|
|
99
|
+
currentActivity.supportFragmentManager.beginTransaction()
|
|
100
|
+
.remove(this)
|
|
101
|
+
.commitAllowingStateLoss()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private fun commitFragmentAndStartFlow(currentActivity: AppCompatActivity) {
|
|
105
|
+
try {
|
|
106
|
+
currentActivity.supportFragmentManager.beginTransaction()
|
|
107
|
+
.add(this, TAG)
|
|
108
|
+
.commit()
|
|
109
|
+
} catch (_: IllegalStateException) {}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.reactnativestripesdk.addresssheet
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.WritableMap
|
|
4
|
+
import com.facebook.react.uimanager.events.Event
|
|
5
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
6
|
+
|
|
7
|
+
internal class AddressSheetEvent constructor(viewTag: Int, private val eventType: EventType, private val eventMap: WritableMap?) : Event<AddressSheetEvent>(viewTag) {
|
|
8
|
+
enum class EventType {
|
|
9
|
+
OnSubmit,
|
|
10
|
+
OnError
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override fun dispatch(rctEventEmitter: RCTEventEmitter) {
|
|
14
|
+
rctEventEmitter.receiveEvent(viewTag, eventName, eventMap)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
const val ON_SUBMIT = "onSubmitAction"
|
|
19
|
+
const val ON_ERROR = "onErrorAction"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override fun getEventName(): String {
|
|
23
|
+
return when (eventType) {
|
|
24
|
+
EventType.OnSubmit -> ON_SUBMIT
|
|
25
|
+
EventType.OnError -> ON_ERROR
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
package com.reactnativestripesdk.addresssheet
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import android.widget.FrameLayout
|
|
6
|
+
import com.facebook.react.bridge.Arguments
|
|
7
|
+
import com.facebook.react.bridge.ReadableMap
|
|
8
|
+
import com.facebook.react.bridge.WritableMap
|
|
9
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
10
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
11
|
+
import com.facebook.react.uimanager.UIManagerModule
|
|
12
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
13
|
+
import com.reactnativestripesdk.buildPaymentSheetAppearance
|
|
14
|
+
import com.reactnativestripesdk.utils.ErrorType
|
|
15
|
+
import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
|
|
16
|
+
import com.reactnativestripesdk.utils.createError
|
|
17
|
+
import com.reactnativestripesdk.utils.toBundleObject
|
|
18
|
+
import com.stripe.android.paymentsheet.PaymentSheet
|
|
19
|
+
import com.stripe.android.paymentsheet.addresselement.AddressDetails
|
|
20
|
+
import com.stripe.android.paymentsheet.addresselement.AddressLauncher
|
|
21
|
+
import com.stripe.android.paymentsheet.addresselement.AddressLauncherResult
|
|
22
|
+
|
|
23
|
+
class AddressSheetView(private val context: ThemedReactContext) : FrameLayout(context) {
|
|
24
|
+
private var eventDispatcher: EventDispatcher? = context.getNativeModule(UIManagerModule::class.java)?.eventDispatcher
|
|
25
|
+
private var isVisible = false
|
|
26
|
+
private var appearanceParams: ReadableMap? = null
|
|
27
|
+
private var defaultAddress: AddressDetails? = null
|
|
28
|
+
private var allowedCountries: Set<String> = emptySet()
|
|
29
|
+
private var buttonTitle: String? = null
|
|
30
|
+
private var sheetTitle: String? = null
|
|
31
|
+
private var googlePlacesApiKey: String? = null
|
|
32
|
+
private var autocompleteCountries: Set<String> = emptySet()
|
|
33
|
+
private var additionalFields: AddressLauncher.AdditionalFieldsConfiguration? = null
|
|
34
|
+
|
|
35
|
+
private fun onSubmit(params: WritableMap) {
|
|
36
|
+
eventDispatcher?.dispatchEvent(
|
|
37
|
+
AddressSheetEvent(id, AddressSheetEvent.EventType.OnSubmit, params)
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private fun onError(params: WritableMap?) {
|
|
42
|
+
eventDispatcher?.dispatchEvent(
|
|
43
|
+
AddressSheetEvent(id, AddressSheetEvent.EventType.OnError, params)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fun setVisible(newVisibility: Boolean) {
|
|
48
|
+
if (newVisibility && !isVisible) {
|
|
49
|
+
launchAddressSheet()
|
|
50
|
+
} else if (!newVisibility && isVisible) {
|
|
51
|
+
Log.w("StripeReactNative", "Programmatically dismissing the Address Sheet is not supported on Android.")
|
|
52
|
+
}
|
|
53
|
+
isVisible = newVisibility
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private fun launchAddressSheet() {
|
|
57
|
+
val appearance = try {
|
|
58
|
+
buildPaymentSheetAppearance(toBundleObject(appearanceParams), context)
|
|
59
|
+
} catch (error: PaymentSheetAppearanceException) {
|
|
60
|
+
onError(createError(ErrorType.Failed.toString(), error))
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
AddressLauncherFragment().presentAddressSheet(
|
|
64
|
+
context,
|
|
65
|
+
appearance,
|
|
66
|
+
defaultAddress,
|
|
67
|
+
allowedCountries,
|
|
68
|
+
buttonTitle,
|
|
69
|
+
sheetTitle,
|
|
70
|
+
googlePlacesApiKey,
|
|
71
|
+
autocompleteCountries,
|
|
72
|
+
additionalFields
|
|
73
|
+
) { error, address ->
|
|
74
|
+
if (address != null) {
|
|
75
|
+
onSubmit(buildResult(address))
|
|
76
|
+
} else {
|
|
77
|
+
onError(error)
|
|
78
|
+
}
|
|
79
|
+
isVisible = false
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fun setAppearance(appearanceParams: ReadableMap) {
|
|
84
|
+
this.appearanceParams = appearanceParams
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun setDefaultValues(defaults: ReadableMap) {
|
|
88
|
+
defaultAddress = buildAddressDetails(defaults)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fun setAdditionalFields(fields: ReadableMap) {
|
|
92
|
+
additionalFields = buildAdditionalFieldsConfiguration(fields)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fun setAllowedCountries(countries: List<String>) {
|
|
96
|
+
allowedCountries = countries.toSet()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fun setAutocompleteCountries(countries: List<String>) {
|
|
100
|
+
autocompleteCountries = countries.toSet()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fun setPrimaryButtonTitle(title: String) {
|
|
104
|
+
buttonTitle = title
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fun setSheetTitle(title: String) {
|
|
108
|
+
sheetTitle = title
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fun setGooglePlacesApiKey(key: String) {
|
|
112
|
+
googlePlacesApiKey = key
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
companion object {
|
|
116
|
+
internal fun buildAddressDetails(bundle: Bundle): AddressDetails {
|
|
117
|
+
return AddressDetails(
|
|
118
|
+
name = bundle.getString("name"),
|
|
119
|
+
address = buildAddress(bundle.getBundle("address")),
|
|
120
|
+
phoneNumber = bundle.getString("phone"),
|
|
121
|
+
isCheckboxSelected = bundle.getBoolean("isCheckboxSelected"),
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
internal fun buildAddressDetails(map: ReadableMap): AddressDetails {
|
|
126
|
+
return buildAddressDetails(toBundleObject(map))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
internal fun buildAddress(bundle: Bundle?): PaymentSheet.Address? {
|
|
130
|
+
if (bundle == null) {
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
return PaymentSheet.Address(
|
|
134
|
+
city = bundle.getString("city"),
|
|
135
|
+
country = bundle.getString("country"),
|
|
136
|
+
line1 = bundle.getString("line1"),
|
|
137
|
+
line2 = bundle.getString("line2"),
|
|
138
|
+
state = bundle.getString("state"),
|
|
139
|
+
postalCode = bundle.getString("postalCode")
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
internal fun getFieldConfiguration(key: String?): AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration {
|
|
144
|
+
return when (key) {
|
|
145
|
+
"hidden" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.HIDDEN
|
|
146
|
+
"optional" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.OPTIONAL
|
|
147
|
+
"required" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED
|
|
148
|
+
else -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.HIDDEN
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
internal fun buildAdditionalFieldsConfiguration(params: ReadableMap): AddressLauncher.AdditionalFieldsConfiguration {
|
|
153
|
+
val phoneConfiguration = getFieldConfiguration(params.getString("phoneNumber"))
|
|
154
|
+
|
|
155
|
+
return AddressLauncher.AdditionalFieldsConfiguration(
|
|
156
|
+
phone = phoneConfiguration,
|
|
157
|
+
checkboxLabel = params.getString("checkboxLabel")
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
internal fun buildResult(addressDetails: AddressDetails): WritableMap {
|
|
162
|
+
val result = WritableNativeMap()
|
|
163
|
+
result.putString("name", addressDetails.name)
|
|
164
|
+
WritableNativeMap().let {
|
|
165
|
+
it.putString("city", addressDetails.address?.city)
|
|
166
|
+
it.putString("country", addressDetails.address?.country)
|
|
167
|
+
it.putString("line1", addressDetails.address?.line1)
|
|
168
|
+
it.putString("line2", addressDetails.address?.line2)
|
|
169
|
+
it.putString("postalCode", addressDetails.address?.postalCode)
|
|
170
|
+
it.putString("state", addressDetails.address?.state)
|
|
171
|
+
result.putMap("address", it)
|
|
172
|
+
}
|
|
173
|
+
result.putString("phone", addressDetails.phoneNumber)
|
|
174
|
+
result.putBoolean("isCheckboxSelected", addressDetails.isCheckboxSelected ?: false)
|
|
175
|
+
return result
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|