@stripe/stripe-react-native 0.71.0 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/android/gradle.properties +1 -1
  2. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementView.kt +7 -103
  3. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorElementViewManager.kt +1 -5
  4. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +0 -26
  5. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +6 -21
  6. package/android/src/main/java/com/reactnativestripesdk/LinkControllerManager.kt +59 -18
  7. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +14 -0
  8. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +6 -50
  9. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +38 -187
  10. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +2 -0
  11. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +4 -0
  12. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +1 -0
  13. package/android/src/test/java/com/reactnativestripesdk/mappers/MappersTest.kt +0 -60
  14. package/ios/CurrencySelectorElementView.swift +18 -129
  15. package/ios/Mappers.swift +2 -0
  16. package/ios/PaymentMethodFactory.swift +14 -1
  17. package/ios/StripeSdk.mm +7 -0
  18. package/ios/StripeSdkImpl+Checkout.swift +35 -259
  19. package/ios/StripeSdkImpl+Embedded.swift +5 -28
  20. package/ios/StripeSdkImpl+LinkController.swift +40 -2
  21. package/ios/StripeSdkImpl+PaymentSheet.swift +2 -15
  22. package/ios/StripeSdkImpl.swift +2 -4
  23. package/lib/commonjs/connect/EmbeddedComponent.js +2 -2
  24. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  25. package/lib/commonjs/functions.js +1 -1
  26. package/lib/commonjs/functions.js.map +1 -1
  27. package/lib/commonjs/hooks/useLinkController.js +1 -1
  28. package/lib/commonjs/hooks/useLinkController.js.map +1 -1
  29. package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
  30. package/lib/commonjs/types/PaymentIntent.js.map +1 -1
  31. package/lib/module/connect/EmbeddedComponent.js +2 -2
  32. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  33. package/lib/module/functions.js +1 -1
  34. package/lib/module/functions.js.map +1 -1
  35. package/lib/module/hooks/useLinkController.js +1 -1
  36. package/lib/module/hooks/useLinkController.js.map +1 -1
  37. package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
  38. package/lib/module/types/PaymentIntent.js.map +1 -1
  39. package/lib/typescript/src/connect/EmbeddedComponent.d.ts +1 -0
  40. package/lib/typescript/src/connect/EmbeddedComponent.d.ts.map +1 -1
  41. package/lib/typescript/src/functions.d.ts +11 -0
  42. package/lib/typescript/src/functions.d.ts.map +1 -1
  43. package/lib/typescript/src/hooks/useLinkController.d.ts +7 -0
  44. package/lib/typescript/src/hooks/useLinkController.d.ts.map +1 -1
  45. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +4 -0
  46. package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
  47. package/lib/typescript/src/types/LinkController.d.ts +10 -5
  48. package/lib/typescript/src/types/LinkController.d.ts.map +1 -1
  49. package/lib/typescript/src/types/PaymentIntent.d.ts +9 -1
  50. package/lib/typescript/src/types/PaymentIntent.d.ts.map +1 -1
  51. package/package.json +1 -1
  52. package/src/connect/EmbeddedComponent.tsx +14 -2
  53. package/src/functions.ts +26 -0
  54. package/src/hooks/useLinkController.tsx +24 -1
  55. package/src/specs/NativeStripeSdkModule.ts +5 -0
  56. package/src/types/LinkController.ts +9 -5
  57. package/src/types/PaymentIntent.ts +11 -1
  58. package/stripe-react-native.podspec +1 -1
  59. package/android/src/main/java/com/reactnativestripesdk/CurrencySelectorAppearance.kt +0 -229
  60. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutAddressUpdate.kt +0 -45
  61. package/android/src/main/java/com/reactnativestripesdk/utils/CheckoutMappers.kt +0 -127
  62. package/android/src/test/java/com/reactnativestripesdk/CurrencySelectorAppearanceTest.kt +0 -137
  63. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutMappersTest.kt +0 -98
  64. package/android/src/test/java/com/reactnativestripesdk/utils/CheckoutTestFixtures.java +0 -57
  65. package/ios/CurrencySelectorAppearance.swift +0 -120
  66. package/ios/Mappers+Checkout.swift +0 -337
@@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=36
3
3
  StripeSdk_targetSdkVersion=36
4
4
  StripeSdk_minSdkVersion=23
5
5
  # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
6
- StripeSdk_stripeVersion=23.12.0
6
+ StripeSdk_stripeVersion=23.13.1
@@ -1,128 +1,32 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
- import android.annotation.SuppressLint
4
3
  import android.content.Context
5
- import androidx.compose.foundation.layout.Box
6
4
  import androidx.compose.runtime.Composable
7
5
  import androidx.compose.runtime.LaunchedEffect
8
- import androidx.compose.runtime.getValue
9
- import androidx.compose.runtime.mutableStateOf
10
- import androidx.compose.runtime.remember
11
- import androidx.compose.runtime.setValue
12
- import androidx.compose.ui.Modifier
13
- import androidx.compose.ui.input.pointer.pointerInput
14
- import androidx.compose.ui.layout.layout
15
- import androidx.compose.ui.layout.onSizeChanged
16
- import androidx.compose.ui.platform.LocalDensity
17
- import androidx.compose.ui.unit.IntOffset
18
- import androidx.compose.ui.unit.dp
19
6
  import com.facebook.react.bridge.Arguments
20
7
  import com.facebook.react.bridge.ReactContext
21
8
  import com.facebook.react.bridge.WritableMap
22
9
  import com.facebook.react.uimanager.UIManagerHelper
23
- import com.stripe.android.checkout.Checkout
24
- import com.stripe.android.paymentelement.CheckoutSessionPreview
25
10
 
26
- @OptIn(CheckoutSessionPreview::class)
27
11
  class CurrencySelectorElementView(
28
12
  context: Context,
29
13
  ) : StripeAbstractComposeView(context) {
30
14
  private val reactContext get() = context as ReactContext
31
15
 
32
- // Backing state for props. mutableStateOf so Compose recomposes on changes.
33
- private var sessionKeyState = mutableStateOf<String?>(null)
34
- private var disabledState = mutableStateOf(false)
35
- private var appearanceState = mutableStateOf(Checkout.CurrencySelectorContentAppearance())
36
-
16
+ @Suppress("UnusedParameter")
37
17
  fun setSessionKey(value: String?) {
38
- sessionKeyState.value = value?.takeIf { it.isNotEmpty() }
18
+ reportHeightChange(0f)
39
19
  }
40
20
 
41
- fun setDisabled(value: Boolean) {
42
- disabledState.value = value
43
- }
21
+ @Suppress("UnusedParameter")
22
+ fun setDisabled(value: Boolean) = Unit
44
23
 
45
- fun setAppearance(value: Checkout.CurrencySelectorContentAppearance) {
46
- appearanceState.value = value
47
- }
24
+ fun setAppearance() = Unit
48
25
 
49
- @SuppressLint("RestrictedApi")
50
26
  @Composable
51
27
  override fun Content() {
52
- val sessionKey by remember { sessionKeyState }
53
- val disabled by remember { disabledState }
54
- val appearance by remember { appearanceState }
55
-
56
- val checkout = remember(sessionKey) {
57
- sessionKey?.let { key ->
58
- val module = reactContext.getNativeModule(StripeSdkModule::class.java)
59
- module?.checkoutInstances?.get(key)
60
- }
61
- }
62
-
63
- if (checkout != null) {
64
- // We don't push state to JS from this view — `StripeSdkModule` already
65
- // observes the same `Checkout` instance and emits a unified
66
- // `checkoutSessionDidChangeState` event that `useCheckout` mirrors into
67
- // its `state`. Keeping the bridge in one place avoids redundant
68
- // round-trips and inconsistencies.
69
- MeasuredCurrencySelector(
70
- reportHeightChange = { reportHeightChange(it) },
71
- ) {
72
- Box {
73
- checkout.CurrencySelectorContent(appearance = appearance)
74
- if (disabled) {
75
- // The Stripe Android composable doesn't yet expose an `isEnabled`
76
- // parameter, so swallow taps with a transparent pointer-input
77
- // overlay while `disabled` is true. The toggle stays visible but
78
- // can't be interacted with.
79
- Box(
80
- Modifier
81
- .matchParentSize()
82
- .pointerInput(Unit) { /* consume all gestures */ },
83
- )
84
- }
85
- }
86
- }
87
- } else {
88
- // No checkout yet: take up zero height so the element collapses.
89
- LaunchedEffect(Unit) {
90
- reportHeightChange(0f)
91
- }
92
- }
93
- }
94
-
95
- @Composable
96
- private fun MeasuredCurrencySelector(
97
- reportHeightChange: (Float) -> Unit,
98
- content: @Composable () -> Unit,
99
- ) {
100
- val density = LocalDensity.current
101
- var heightDp by remember { mutableStateOf(1.dp) } // non-zero sentinel
102
-
103
- Box(
104
- Modifier
105
- .onSizeChanged { size ->
106
- val h = with(density) { size.height.toDp() }
107
- if (h != heightDp) {
108
- heightDp = h
109
- reportHeightChange(h.value)
110
- }
111
- }
112
- .layout { measurable, constraints ->
113
- val widthPx = constraints.maxWidth
114
- val minHpx = measurable.minIntrinsicHeight(widthPx).coerceAtLeast(0)
115
-
116
- val placeable = measurable.measure(
117
- constraints.copy(minHeight = minHpx, maxHeight = minHpx),
118
- )
119
-
120
- layout(constraints.maxWidth, placeable.height) {
121
- placeable.placeRelative(IntOffset.Zero)
122
- }
123
- },
124
- ) {
125
- content()
28
+ LaunchedEffect(Unit) {
29
+ reportHeightChange(0f)
126
30
  }
127
31
  }
128
32
 
@@ -1,16 +1,13 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
- import com.facebook.react.bridge.ReadableType
5
4
  import com.facebook.react.module.annotations.ReactModule
6
5
  import com.facebook.react.uimanager.ThemedReactContext
7
6
  import com.facebook.react.uimanager.ViewGroupManager
8
7
  import com.facebook.react.uimanager.annotations.ReactProp
9
8
  import com.facebook.react.viewmanagers.StripeCurrencySelectorElementManagerDelegate
10
9
  import com.facebook.react.viewmanagers.StripeCurrencySelectorElementManagerInterface
11
- import com.stripe.android.paymentelement.CheckoutSessionPreview
12
10
 
13
- @OptIn(CheckoutSessionPreview::class)
14
11
  @ReactModule(name = CurrencySelectorElementViewManager.NAME)
15
12
  class CurrencySelectorElementViewManager :
16
13
  ViewGroupManager<CurrencySelectorElementView>(),
@@ -64,7 +61,6 @@ class CurrencySelectorElementViewManager :
64
61
  view: CurrencySelectorElementView,
65
62
  value: Dynamic?,
66
63
  ) {
67
- val appearanceParams = if (value?.type == ReadableType.Map) value.asMap() else null
68
- view.setAppearance(buildCurrencySelectorAppearance(appearanceParams, view.context))
64
+ view.setAppearance()
69
65
  }
70
66
  }
@@ -25,9 +25,7 @@ import com.reactnativestripesdk.utils.KeepJsAwakeTask
25
25
  import com.reactnativestripesdk.utils.mapFromConfirmationToken
26
26
  import com.reactnativestripesdk.utils.mapFromCustomPaymentMethod
27
27
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
28
- import com.stripe.android.checkout.Checkout
29
28
  import com.stripe.android.model.PaymentMethod
30
- import com.stripe.android.paymentelement.CheckoutSessionPreview
31
29
  import com.stripe.android.paymentelement.CustomPaymentMethodResult
32
30
  import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
33
31
  import com.stripe.android.paymentelement.EmbeddedPaymentElement
@@ -45,7 +43,6 @@ enum class RowSelectionBehaviorType {
45
43
  ImmediateAction,
46
44
  }
47
45
 
48
- @OptIn(CheckoutSessionPreview::class)
49
46
  class EmbeddedPaymentElementView(
50
47
  context: Context,
51
48
  ) : StripeAbstractComposeView(context) {
@@ -55,11 +52,6 @@ class EmbeddedPaymentElementView(
55
52
  val intentConfiguration: PaymentSheet.IntentConfiguration,
56
53
  ) : Event
57
54
 
58
- data class ConfigureWithCheckout(
59
- val configuration: EmbeddedPaymentElement.Configuration,
60
- val checkout: Checkout,
61
- ) : Event
62
-
63
55
  data class Update(
64
56
  val intentConfiguration: PaymentSheet.IntentConfiguration,
65
57
  ) : Event
@@ -71,8 +63,6 @@ class EmbeddedPaymentElementView(
71
63
 
72
64
  var latestIntentConfig: PaymentSheet.IntentConfiguration? = null
73
65
  var latestElementConfig: EmbeddedPaymentElement.Configuration? = null
74
- var latestCheckout: Checkout? = null
75
-
76
66
  val rowSelectionBehaviorType = mutableStateOf<RowSelectionBehaviorType?>(null)
77
67
  val useConfirmationTokenCallback = mutableStateOf(false)
78
68
 
@@ -320,15 +310,6 @@ class EmbeddedPaymentElementView(
320
310
  )
321
311
  }
322
312
 
323
- is Event.ConfigureWithCheckout -> {
324
- handleConfigureResult(
325
- embedded.configure(
326
- checkout = ev.checkout,
327
- configuration = ev.configuration,
328
- ),
329
- )
330
- }
331
-
332
313
  is Event.Update -> {
333
314
  val elemConfig = latestElementConfig ?: return@collect emitUpdateMissingConfiguration()
334
315
 
@@ -477,13 +458,6 @@ class EmbeddedPaymentElementView(
477
458
  events.trySend(Event.Configure(config, intentConfig))
478
459
  }
479
460
 
480
- fun configureWithCheckout(
481
- config: EmbeddedPaymentElement.Configuration,
482
- checkout: Checkout,
483
- ) {
484
- events.trySend(Event.ConfigureWithCheckout(config, checkout))
485
- }
486
-
487
461
  fun update(intentConfig: PaymentSheet.IntentConfiguration) {
488
462
  events.trySend(Event.Update(intentConfig))
489
463
  }
@@ -23,7 +23,6 @@ import com.reactnativestripesdk.utils.getStringList
23
23
  import com.reactnativestripesdk.utils.mapToPreferredNetworks
24
24
  import com.reactnativestripesdk.utils.parseCustomPaymentMethods
25
25
  import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
26
- import com.stripe.android.paymentelement.CheckoutSessionPreview
27
26
  import com.stripe.android.paymentelement.EmbeddedPaymentElement
28
27
  import com.stripe.android.paymentsheet.CardFundingFilteringPrivatePreview
29
28
  import com.stripe.android.paymentsheet.PaymentSheet
@@ -31,7 +30,6 @@ import org.json.JSONArray
31
30
  import org.json.JSONObject
32
31
 
33
32
  @ReactModule(name = EmbeddedPaymentElementViewManager.NAME)
34
- @OptIn(CheckoutSessionPreview::class)
35
33
  @Suppress("TooManyFunctions")
36
34
  class EmbeddedPaymentElementViewManager :
37
35
  ViewGroupManager<EmbeddedPaymentElementView>(),
@@ -95,37 +93,24 @@ class EmbeddedPaymentElementViewManager :
95
93
  view: EmbeddedPaymentElementView,
96
94
  cfg: Dynamic,
97
95
  ) {
98
- val sessionKey = cfg.asMapOrNull()?.getString("sessionKey") ?: return
99
-
100
96
  val stripeSdkModule =
101
97
  (view.context as ThemedReactContext).getNativeModule(StripeSdkModule::class.java)
102
- val checkout = stripeSdkModule?.checkoutInstances?.get(sessionKey)
103
- if (checkout == null) {
104
- val payload =
105
- Arguments.createMap().apply {
106
- putString("message", "Checkout session not found.")
107
- }
108
- stripeSdkModule?.eventEmitter?.emitEmbeddedPaymentElementLoadingFailed(payload)
109
- return
110
- }
111
-
112
- view.latestCheckout = checkout
113
- view.latestElementConfig?.let { configureIfReady(view, it) }
98
+ val payload =
99
+ Arguments.createMap().apply {
100
+ putString("message", CHECKOUT_UNAVAILABLE_MESSAGE)
101
+ }
102
+ stripeSdkModule?.eventEmitter?.emitEmbeddedPaymentElementLoadingFailed(payload)
114
103
  }
115
104
 
116
105
  /**
117
106
  * Configures the embedded element once both the element config and an
118
- * intent source (intent configuration or checkout) have arrived. Returns
107
+ * intent configuration have arrived. Returns
119
108
  * `true` when a configure was dispatched.
120
109
  */
121
110
  private fun configureIfReady(
122
111
  view: EmbeddedPaymentElementView,
123
112
  elementConfig: EmbeddedPaymentElement.Configuration,
124
113
  ): Boolean {
125
- view.latestCheckout?.let { checkout ->
126
- view.configureWithCheckout(elementConfig, checkout)
127
- return true
128
- }
129
114
  view.latestIntentConfig?.let { intentCfg ->
130
115
  view.configure(elementConfig, intentCfg)
131
116
  return true
@@ -1,5 +1,6 @@
1
1
  package com.reactnativestripesdk
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import androidx.activity.ComponentActivity
4
5
  import androidx.lifecycle.SavedStateHandle
5
6
  import androidx.lifecycle.lifecycleScope
@@ -33,7 +34,9 @@ internal class LinkControllerManager(
33
34
  private var linkController: LinkController? = null
34
35
  private var linkPresenter: LinkController.Presenter? = null
35
36
  private var presentPromise: Promise? = null
37
+ private var confirmSetupIntentPromise: Promise? = null
36
38
 
39
+ @SuppressLint("RestrictedApi", "VisibleForTests")
37
40
  fun configure(params: ReadableMap, promise: Promise) {
38
41
  val email = params.getString("email")
39
42
  val merchantDisplayName = params.getString("merchantDisplayName")
@@ -50,9 +53,8 @@ internal class LinkControllerManager(
50
53
 
51
54
  val phoneNumber = params.getString("phoneNumber")
52
55
  val allowLogout = if (params.hasKey("allowLogout")) params.getBoolean("allowLogout") else true
53
- val setupIntentClientSecret = params.getString("setupIntentClientSecret")
54
-
55
56
  val supportedTypes = parseSupportedPaymentMethodTypes(params)
57
+ val paymentMethodTypes = parsePaymentMethodTypes(params)
56
58
 
57
59
  val config = LinkController.Configuration(
58
60
  merchantDisplayName = merchantDisplayName,
@@ -62,8 +64,8 @@ internal class LinkControllerManager(
62
64
  .also { if (email != null) it.email(email) }
63
65
  .phoneNumber(phoneNumber)
64
66
  .supportedPaymentMethodTypes(supportedTypes)
67
+ .also { if (paymentMethodTypes != null) it.paymentMethodTypes(paymentMethodTypes) }
65
68
  .allowLogout(allowLogout)
66
- .setupIntentClientSecret(setupIntentClientSecret)
67
69
 
68
70
  // Build a new controller if this is the first call or after a reset.
69
71
  // SavedStateHandle() is empty — state will not survive process death, which is
@@ -84,7 +86,11 @@ internal class LinkControllerManager(
84
86
  if (linkPresenter == null) {
85
87
  linkPresenter = controller.createPresenter(
86
88
  activity = activity,
87
- presentCallback = { presentResult -> handlePresentResult(presentResult) }
89
+ presentPaymentMethodsCallback = { },
90
+ authenticationCallback = { },
91
+ authorizeCallback = { },
92
+ presentCallback = { presentResult -> handlePresentResult(presentResult) },
93
+ confirmSetupIntentCallback = { result -> handleConfirmSetupIntentResult(result) }
88
94
  )
89
95
  }
90
96
  promise.resolve(Arguments.createMap())
@@ -110,10 +116,22 @@ internal class LinkControllerManager(
110
116
  presenter.present()
111
117
  }
112
118
 
119
+ fun confirmSetupIntent(clientSecret: String, promise: Promise) {
120
+ val presenter = linkPresenter
121
+ if (presenter == null) {
122
+ promise.resolve(createError(ErrorType.Failed.toString(), LINK_CONTROLLER_NOT_INITIALIZED_ERROR))
123
+ return
124
+ }
125
+
126
+ confirmSetupIntentPromise = promise
127
+ presenter.confirmSetupIntent(clientSecret)
128
+ }
129
+
113
130
  fun destroy() {
114
131
  linkController = null
115
132
  linkPresenter = null
116
133
  presentPromise = null
134
+ confirmSetupIntentPromise = null
117
135
  }
118
136
 
119
137
  private fun parseSupportedPaymentMethodTypes(params: ReadableMap): List<LinkController.PaymentMethodType>? =
@@ -127,6 +145,27 @@ internal class LinkControllerManager(
127
145
  }.ifEmpty { null }
128
146
  }
129
147
 
148
+ private fun parsePaymentMethodTypes(params: ReadableMap): List<String>? =
149
+ params.getArray("paymentMethodTypes")?.let { arr ->
150
+ (0 until arr.size()).mapNotNull { i -> arr.getString(i) }.ifEmpty { null }
151
+ }
152
+
153
+ private fun handleConfirmSetupIntentResult(result: LinkController.ConfirmSetupIntentResult) {
154
+ val promise = confirmSetupIntentPromise ?: return
155
+ confirmSetupIntentPromise = null
156
+ when (result) {
157
+ is LinkController.ConfirmSetupIntentResult.Success -> {
158
+ promise.resolve(Arguments.createMap())
159
+ }
160
+ is LinkController.ConfirmSetupIntentResult.Canceled -> {
161
+ promise.resolve(createError(ErrorType.Canceled.toString(), "SetupIntent confirmation was canceled."))
162
+ }
163
+ is LinkController.ConfirmSetupIntentResult.Failed -> {
164
+ promise.resolve(createError(ErrorType.Failed.toString(), result.error))
165
+ }
166
+ }
167
+ }
168
+
130
169
  private fun handlePresentResult(result: LinkController.PresentResult) {
131
170
  val promise = presentPromise ?: return
132
171
  val controller = linkController ?: return
@@ -135,24 +174,26 @@ internal class LinkControllerManager(
135
174
  val response = Arguments.createMap()
136
175
  response.putMap("paymentMethod", mapFromPaymentMethod(result.paymentMethod))
137
176
 
138
- val preview = controller.paymentMethodPreview.value
139
177
  val currentScope = (context.currentActivity as? ComponentActivity)?.lifecycleScope
140
- if (preview != null && currentScope != null) {
178
+ if (currentScope != null) {
141
179
  currentScope.launch {
142
- val iconBase64 = withContext(Dispatchers.IO) {
143
- try {
144
- convertDrawableToBase64(preview.icon)
145
- } catch (_: Exception) {
146
- null
180
+ val preview = controller.paymentMethodPreview.value
181
+ if (preview != null) {
182
+ val iconBase64 = withContext(Dispatchers.IO) {
183
+ try {
184
+ convertDrawableToBase64(preview.icon)
185
+ } catch (_: Exception) {
186
+ null
187
+ }
147
188
  }
189
+ val previewMap = Arguments.createMap()
190
+ previewMap.putString("label", preview.label)
191
+ preview.sublabel?.let { previewMap.putString("sublabel", it) }
192
+ if (iconBase64 != null) {
193
+ previewMap.putString("icon", "data:image/png;base64,$iconBase64")
194
+ }
195
+ response.putMap("paymentMethodPreview", previewMap)
148
196
  }
149
- val previewMap = Arguments.createMap()
150
- previewMap.putString("label", preview.label)
151
- preview.sublabel?.let { previewMap.putString("sublabel", it) }
152
- if (iconBase64 != null) {
153
- previewMap.putString("icon", "data:image/png;base64,$iconBase64")
154
- }
155
- response.putMap("paymentMethodPreview", previewMap)
156
197
  promise.resolve(response)
157
198
  }
158
199
  } else {
@@ -57,6 +57,7 @@ class PaymentMethodCreateParamsFactory(
57
57
  PaymentMethod.Type.CashAppPay -> createCashAppParams()
58
58
  PaymentMethod.Type.RevolutPay -> createRevolutPayParams()
59
59
  PaymentMethod.Type.PayByBank -> createPayByBankParams()
60
+ PaymentMethod.Type.Twint -> createTwintParams()
60
61
  else -> {
61
62
  throw Exception("This paymentMethodType is not supported yet")
62
63
  }
@@ -100,6 +101,18 @@ class PaymentMethodCreateParamsFactory(
100
101
  throw PaymentMethodCreateParamsException("You must provide billing details")
101
102
  }
102
103
 
104
+ @Throws(PaymentMethodCreateParamsException::class)
105
+ private fun createTwintParams(): PaymentMethodCreateParams {
106
+ billingDetailsParams?.let {
107
+ return PaymentMethodCreateParams.createTwint(
108
+ billingDetails = it,
109
+ metadata = metadataParams,
110
+ )
111
+ }
112
+
113
+ throw PaymentMethodCreateParamsException("You must provide billing details")
114
+ }
115
+
103
116
  @Throws(PaymentMethodCreateParamsException::class)
104
117
  private fun createBillieParams(): PaymentMethodCreateParams =
105
118
  PaymentMethodCreateParams.createBillie(
@@ -297,6 +310,7 @@ class PaymentMethodCreateParamsFactory(
297
310
  PaymentMethod.Type.CashAppPay,
298
311
  PaymentMethod.Type.RevolutPay,
299
312
  PaymentMethod.Type.PayByBank,
313
+ PaymentMethod.Type.Twint,
300
314
  -> {
301
315
  val params = createPaymentMethodParams(paymentMethodType)
302
316
 
@@ -39,10 +39,8 @@ import com.reactnativestripesdk.utils.mapFromPaymentMethod
39
39
  import com.reactnativestripesdk.utils.mapToPreferredNetworks
40
40
  import com.reactnativestripesdk.utils.parseCustomPaymentMethods
41
41
  import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
42
- import com.stripe.android.checkout.Checkout
43
42
  import com.stripe.android.core.reactnative.ReactNativeSdkInternal
44
43
  import com.stripe.android.model.PaymentMethod
45
- import com.stripe.android.paymentelement.CheckoutSessionPreview
46
44
  import com.stripe.android.paymentelement.ConfirmCustomPaymentMethodCallback
47
45
  import com.stripe.android.paymentelement.CreateIntentWithConfirmationTokenCallback
48
46
  import com.stripe.android.paymentelement.CustomPaymentMethodResult
@@ -69,13 +67,11 @@ import kotlin.coroutines.resume
69
67
  ReactNativeSdkInternal::class,
70
68
  ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class,
71
69
  CardFundingFilteringPrivatePreview::class,
72
- CheckoutSessionPreview::class,
73
70
  )
74
71
  class PaymentSheetManager(
75
72
  context: ReactApplicationContext,
76
73
  private val arguments: ReadableMap,
77
74
  private val initPromise: Promise,
78
- private val checkoutInstances: Map<String, Checkout>,
79
75
  ) : StripeUIManager(context),
80
76
  ConfirmCustomPaymentMethodCallback {
81
77
  private var paymentSheet: PaymentSheet? = null
@@ -83,7 +79,6 @@ class PaymentSheetManager(
83
79
  private var paymentIntentClientSecret: String? = null
84
80
  private var setupIntentClientSecret: String? = null
85
81
  private var intentConfiguration: PaymentSheet.IntentConfiguration? = null
86
- private var checkoutSessionKey: String? = null
87
82
  private lateinit var paymentSheetConfiguration: PaymentSheet.Configuration
88
83
  private var confirmPromise: Promise? = null
89
84
  private var paymentSheetTimedOut = false
@@ -101,13 +96,17 @@ class PaymentSheetManager(
101
96
  super.onDestroy()
102
97
  flowController = null
103
98
  paymentSheet = null
104
- checkoutSessionKey = null
105
99
  }
106
100
 
107
101
  fun configure(
108
102
  args: ReadableMap,
109
103
  promise: Promise,
110
104
  ) {
105
+ if (args.hasKey("checkout")) {
106
+ promise.resolve(createCheckoutUnavailableError())
107
+ return
108
+ }
109
+
111
110
  val merchantDisplayName = args.getString("merchantDisplayName").orEmpty()
112
111
  if (merchantDisplayName.isEmpty()) {
113
112
  promise.resolve(
@@ -115,9 +114,6 @@ class PaymentSheetManager(
115
114
  )
116
115
  return
117
116
  }
118
- if (!resolveCheckoutSessionOrReturn(args, promise)) {
119
- return
120
- }
121
117
 
122
118
  val primaryButtonLabel = args.getString("primaryButtonLabel")
123
119
  val googlePayConfig = buildGooglePayConfig(args.getMap("googlePay"))
@@ -189,21 +185,6 @@ class PaymentSheetManager(
189
185
  configureMode(args, promise)
190
186
  }
191
187
 
192
- private fun resolveCheckoutSessionOrReturn(
193
- args: ReadableMap,
194
- promise: Promise,
195
- ): Boolean {
196
- checkoutSessionKey = args.getMap("checkout")?.getString("sessionKey")
197
- val checkoutSessionKey = checkoutSessionKey ?: return true
198
- checkoutInstances[checkoutSessionKey] ?: run {
199
- promise.resolve(
200
- createError(ErrorType.Failed.toString(), "Checkout session not found."),
201
- )
202
- return false
203
- }
204
- return true
205
- }
206
-
207
188
  private inline fun <T> resolvePaymentSheetValue(
208
189
  promise: Promise,
209
190
  builder: () -> T,
@@ -239,16 +220,6 @@ class PaymentSheetManager(
239
220
  return
240
221
  }
241
222
 
242
- if (checkoutSessionKey != null) {
243
- promise.resolve(
244
- createError(
245
- ErrorType.Failed.toString(),
246
- "PaymentSheet with checkout is not supported. Use customFlow: true instead.",
247
- ),
248
- )
249
- return
250
- }
251
-
252
223
  lastConfigureWasCustomFlow = false
253
224
  if (paymentSheet == null) {
254
225
  initPaymentSheet(args, promise)
@@ -525,14 +496,7 @@ class PaymentSheetManager(
525
496
  handleFlowControllerConfigured(success, error, promise, flowController)
526
497
  }
527
498
 
528
- val checkout = getCheckoutInstanceOrResolveError(promise)
529
- if (checkout != null) {
530
- flowController?.configureWithCheckout(
531
- checkout = checkout,
532
- configuration = paymentSheetConfiguration,
533
- callback = onFlowControllerConfigure,
534
- )
535
- } else if (!paymentIntentClientSecret.isNullOrEmpty()) {
499
+ if (!paymentIntentClientSecret.isNullOrEmpty()) {
536
500
  flowController?.configureWithPaymentIntent(
537
501
  paymentIntentClientSecret = paymentIntentClientSecret!!,
538
502
  configuration = paymentSheetConfiguration,
@@ -561,14 +525,6 @@ class PaymentSheetManager(
561
525
  }
562
526
  }
563
527
 
564
- private fun getCheckoutInstanceOrResolveError(promise: Promise?): Checkout? {
565
- val checkoutSessionKey = checkoutSessionKey ?: return null
566
- return checkoutInstances[checkoutSessionKey] ?: run {
567
- promise?.resolve(createError(ErrorType.Failed.toString(), "Checkout session not found."))
568
- null
569
- }
570
- }
571
-
572
528
  private fun resolvePresentPromise(value: Any?) {
573
529
  keepJsAwake?.stop()
574
530
  promise?.resolve(value)