@stripe/stripe-react-native 0.59.1 → 0.60.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 (142) hide show
  1. package/README.md +6 -3
  2. package/android/gradle.properties +2 -2
  3. package/android/src/main/java/com/reactnativestripesdk/FakeOnrampSdkModule.kt +2 -7
  4. package/android/src/main/java/com/reactnativestripesdk/PaymentElementConfig.kt +20 -0
  5. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodMessagingElementConfig.kt +1 -1
  6. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +124 -88
  7. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +12 -9
  8. package/android/src/oldarch/java/com/reactnativestripesdk/NativeOnrampSdkModuleSpec.java +0 -4
  9. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +6 -5
  10. package/android/src/onramp/java/com/reactnativestripesdk/OnrampMappers.kt +157 -0
  11. package/android/src/onramp/java/com/reactnativestripesdk/OnrampSdkModule.kt +130 -189
  12. package/android/src/test/java/com/reactnativestripesdk/PaymentElementConfigTest.kt +72 -0
  13. package/android/src/test/java/com/reactnativestripesdk/PaymentMethodMessagingElementConfigTest.kt +3 -3
  14. package/android/src/test/java/com/reactnativestripesdk/mappers/OnrampMappersTest.kt +219 -0
  15. package/ios/Mappers.swift +10 -0
  16. package/ios/PaymentMethodMessagingElementConfig.swift +1 -1
  17. package/ios/StripeOnrampSdk.mm +0 -6
  18. package/ios/StripeSdkImpl+PaymentSheet.swift +25 -0
  19. package/ios/StripeSdkImpl.swift +5 -37
  20. package/jest/mock.js +1 -1
  21. package/jest/setup.js +0 -1
  22. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  23. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  24. package/lib/commonjs/components/AddressSheet.js +1 -1
  25. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  26. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  27. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  28. package/lib/commonjs/components/CardField.js +1 -1
  29. package/lib/commonjs/components/CardField.js.map +1 -1
  30. package/lib/commonjs/components/CardForm.js +1 -1
  31. package/lib/commonjs/components/CardForm.js.map +1 -1
  32. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  33. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  34. package/lib/commonjs/components/StripeContainer.js +1 -1
  35. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  36. package/lib/commonjs/connect/Components.js +1 -1
  37. package/lib/commonjs/connect/Components.js.map +1 -1
  38. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  39. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  40. package/lib/commonjs/connect/EmbeddedComponent.js +1 -1
  41. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  42. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  43. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  44. package/lib/commonjs/connect/NavigationBar.js +1 -1
  45. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  46. package/lib/commonjs/helpers.js +1 -1
  47. package/lib/commonjs/hooks/useOnramp.js +1 -1
  48. package/lib/commonjs/hooks/useOnramp.js.map +1 -1
  49. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  50. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  51. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  52. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  53. package/lib/commonjs/specs/NativeCardField.js +1 -1
  54. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  55. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  56. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  57. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  58. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  59. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  60. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  61. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  62. package/lib/commonjs/specs/NativeOnrampSdkModule.js.map +1 -1
  63. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  64. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  65. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  66. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  67. package/lib/commonjs/types/Onramp.js.map +1 -1
  68. package/lib/commonjs/types/PaymentSheet.js +1 -1
  69. package/lib/commonjs/types/PaymentSheet.js.map +1 -1
  70. package/lib/module/components/AddToWalletButton.js +1 -1
  71. package/lib/module/components/AddToWalletButton.js.map +1 -1
  72. package/lib/module/components/AddressSheet.js +1 -1
  73. package/lib/module/components/AddressSheet.js.map +1 -1
  74. package/lib/module/components/AuBECSDebitForm.js +1 -1
  75. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  76. package/lib/module/components/CardField.js +1 -1
  77. package/lib/module/components/CardField.js.map +1 -1
  78. package/lib/module/components/CardForm.js +1 -1
  79. package/lib/module/components/CardForm.js.map +1 -1
  80. package/lib/module/components/PlatformPayButton.js +1 -1
  81. package/lib/module/components/PlatformPayButton.js.map +1 -1
  82. package/lib/module/components/StripeContainer.js +1 -1
  83. package/lib/module/components/StripeContainer.js.map +1 -1
  84. package/lib/module/connect/Components.js +1 -1
  85. package/lib/module/connect/Components.js.map +1 -1
  86. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  87. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  88. package/lib/module/connect/EmbeddedComponent.js +1 -1
  89. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  90. package/lib/module/connect/ModalCloseButton.js +1 -1
  91. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  92. package/lib/module/connect/NavigationBar.js +1 -1
  93. package/lib/module/connect/NavigationBar.js.map +1 -1
  94. package/lib/module/helpers.js +1 -1
  95. package/lib/module/hooks/useOnramp.js +1 -1
  96. package/lib/module/hooks/useOnramp.js.map +1 -1
  97. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  98. package/lib/module/specs/NativeAddressSheet.js +1 -1
  99. package/lib/module/specs/NativeApplePayButton.js +1 -1
  100. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  101. package/lib/module/specs/NativeCardField.js +1 -1
  102. package/lib/module/specs/NativeCardField.js.map +1 -1
  103. package/lib/module/specs/NativeCardForm.js +1 -1
  104. package/lib/module/specs/NativeCardForm.js.map +1 -1
  105. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  106. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  107. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  108. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  109. package/lib/module/specs/NativeNavigationBar.js +1 -1
  110. package/lib/module/specs/NativeOnrampSdkModule.js.map +1 -1
  111. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  112. package/lib/module/specs/NativeStripeContainer.js +1 -1
  113. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  114. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  115. package/lib/module/types/Onramp.js.map +1 -1
  116. package/lib/module/types/PaymentSheet.js +1 -1
  117. package/lib/module/types/PaymentSheet.js.map +1 -1
  118. package/lib/typescript/src/hooks/useOnramp.d.ts +3 -9
  119. package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
  120. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts +0 -1
  121. package/lib/typescript/src/specs/NativeOnrampSdkModule.d.ts.map +1 -1
  122. package/lib/typescript/src/types/Onramp.d.ts +30 -12
  123. package/lib/typescript/src/types/Onramp.d.ts.map +1 -1
  124. package/lib/typescript/src/types/PaymentSheet.d.ts +22 -0
  125. package/lib/typescript/src/types/PaymentSheet.d.ts.map +1 -1
  126. package/lib/typescript/src/types/index.d.ts +0 -5
  127. package/lib/typescript/src/types/index.d.ts.map +1 -1
  128. package/package.json +3 -2
  129. package/src/hooks/useOnramp.tsx +9 -17
  130. package/src/specs/NativeOnrampSdkModule.ts +0 -1
  131. package/src/types/Onramp.ts +32 -15
  132. package/src/types/PaymentSheet.ts +23 -0
  133. package/src/types/index.ts +0 -6
  134. package/stripe-react-native.podspec +1 -1
  135. package/android/.idea/AndroidProjectSystem.xml +0 -6
  136. package/android/.idea/compiler.xml +0 -6
  137. package/android/.idea/gradle.xml +0 -18
  138. package/android/.idea/migrations.xml +0 -10
  139. package/android/.idea/misc.xml +0 -10
  140. package/android/.idea/runConfigurations.xml +0 -17
  141. package/android/.idea/vcs.xml +0 -6
  142. package/android/local.properties +0 -8
@@ -3,8 +3,6 @@ package com.reactnativestripesdk
3
3
  import android.annotation.SuppressLint
4
4
  import android.app.Application
5
5
  import androidx.activity.ComponentActivity
6
- import androidx.compose.ui.graphics.Color
7
- import androidx.core.content.ContextCompat
8
6
  import androidx.fragment.app.FragmentActivity
9
7
  import androidx.lifecycle.SavedStateHandle
10
8
  import com.facebook.react.bridge.Arguments
@@ -30,12 +28,10 @@ import com.stripe.android.crypto.onramp.model.CryptoNetwork
30
28
  import com.stripe.android.crypto.onramp.model.KycInfo
31
29
  import com.stripe.android.crypto.onramp.model.LinkUserInfo
32
30
  import com.stripe.android.crypto.onramp.model.OnrampAttachKycInfoResult
33
- import com.stripe.android.crypto.onramp.model.OnrampAuthenticateResult
34
31
  import com.stripe.android.crypto.onramp.model.OnrampAuthorizeResult
35
32
  import com.stripe.android.crypto.onramp.model.OnrampCallbacks
36
33
  import com.stripe.android.crypto.onramp.model.OnrampCheckoutResult
37
34
  import com.stripe.android.crypto.onramp.model.OnrampCollectPaymentMethodResult
38
- import com.stripe.android.crypto.onramp.model.OnrampConfiguration
39
35
  import com.stripe.android.crypto.onramp.model.OnrampConfigurationResult
40
36
  import com.stripe.android.crypto.onramp.model.OnrampCreateCryptoPaymentTokenResult
41
37
  import com.stripe.android.crypto.onramp.model.OnrampHasLinkAccountResult
@@ -46,11 +42,7 @@ import com.stripe.android.crypto.onramp.model.OnrampTokenAuthenticationResult
46
42
  import com.stripe.android.crypto.onramp.model.OnrampUpdatePhoneNumberResult
47
43
  import com.stripe.android.crypto.onramp.model.OnrampVerifyIdentityResult
48
44
  import com.stripe.android.crypto.onramp.model.OnrampVerifyKycInfoResult
49
- import com.stripe.android.crypto.onramp.model.PaymentMethodType
50
- import com.stripe.android.link.LinkAppearance
51
- import com.stripe.android.link.LinkAppearance.Colors
52
- import com.stripe.android.link.LinkAppearance.PrimaryButton
53
- import com.stripe.android.link.LinkAppearance.Style
45
+ import com.stripe.android.crypto.onramp.model.PaymentMethodSelection
54
46
  import com.stripe.android.link.LinkController.PaymentMethodPreview
55
47
  import com.stripe.android.link.PaymentMethodPreviewDetails
56
48
  import com.stripe.android.model.CardBrand
@@ -59,8 +51,11 @@ import com.stripe.android.paymentsheet.PaymentSheet
59
51
  import kotlinx.coroutines.CompletableDeferred
60
52
  import kotlinx.coroutines.CoroutineScope
61
53
  import kotlinx.coroutines.Dispatchers
54
+ import kotlinx.coroutines.SupervisorJob
55
+ import kotlinx.coroutines.cancel
62
56
  import kotlinx.coroutines.launch
63
57
  import kotlinx.coroutines.withContext
58
+ import kotlinx.coroutines.withTimeout
64
59
 
65
60
  @SuppressLint("RestrictedApi")
66
61
  @ReactModule(name = NativeOnrampSdkModuleSpec.NAME)
@@ -81,6 +76,7 @@ class OnrampSdkModule(
81
76
  private var verifyKycPromise: Promise? = null
82
77
 
83
78
  private var checkoutClientSecretDeferred: CompletableDeferred<String>? = null
79
+ private val rnScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
84
80
 
85
81
  @ReactMethod
86
82
  override fun initialise(
@@ -95,6 +91,11 @@ class OnrampSdkModule(
95
91
  promise.resolve(null)
96
92
  }
97
93
 
94
+ override fun invalidate() {
95
+ super.invalidate()
96
+ rnScope.cancel()
97
+ }
98
+
98
99
  /**
99
100
  * Safely get and cast the current activity as an AppCompatActivity. If that fails, the promise
100
101
  * provided will be resolved with an error message instructing the user to retry the method.
@@ -124,33 +125,37 @@ class OnrampSdkModule(
124
125
  return
125
126
  }
126
127
 
128
+ val onrampCallbacks =
129
+ OnrampCallbacks()
130
+ .verifyIdentityCallback { result ->
131
+ handleOnrampIdentityVerificationResult(result, identityVerificationPromise!!)
132
+ }.collectPaymentCallback { result ->
133
+ handleOnrampCollectPaymentResult(result, collectPaymentPromise!!)
134
+ }.authorizeCallback { result ->
135
+ handleOnrampAuthorizationResult(result, authorizePromise!!)
136
+ }.checkoutCallback { result ->
137
+ handleOnrampCheckoutResult(result, checkoutPromise!!)
138
+ }.verifyKycCallback { result ->
139
+ handleOnrampKycVerificationResult(result, verifyKycPromise!!)
140
+ }.onrampSessionClientSecretProvider { sessionId ->
141
+ checkoutClientSecretDeferred = CompletableDeferred()
142
+
143
+ val params = Arguments.createMap()
144
+ params.putString("onrampSessionId", sessionId)
145
+
146
+ emitOnCheckoutClientSecretRequested(params)
147
+
148
+ checkoutClientSecretDeferred!!.await()
149
+ }
150
+
127
151
  val coordinator =
128
152
  onrampCoordinator ?: OnrampCoordinator
129
153
  .Builder()
130
- .build(application, SavedStateHandle())
154
+ .build(application, SavedStateHandle(), onrampCallbacks)
131
155
  .also { this.onrampCoordinator = it }
132
156
 
133
157
  CoroutineScope(Dispatchers.IO).launch {
134
- val appearanceMap = config.getMap("appearance")
135
- val appearance =
136
- if (appearanceMap != null) {
137
- mapAppearance(appearanceMap)
138
- } else {
139
- LinkAppearance(style = Style.AUTOMATIC)
140
- }
141
-
142
- val displayName = config.getString("merchantDisplayName") ?: ""
143
-
144
- val cryptoCustomerId = config.getString("cryptoCustomerId")
145
-
146
- val configuration =
147
- OnrampConfiguration(
148
- merchantDisplayName = displayName,
149
- publishableKey = publishableKey,
150
- appearance = appearance,
151
- cryptoCustomerId = cryptoCustomerId,
152
- )
153
-
158
+ val configuration = mapConfig(config, publishableKey)
154
159
  val configureResult = coordinator.configure(configuration)
155
160
 
156
161
  CoroutineScope(Dispatchers.Main).launch {
@@ -182,30 +187,8 @@ class OnrampSdkModule(
182
187
  return
183
188
  }
184
189
 
185
- val onrampCallbacks =
186
- OnrampCallbacks(
187
- authenticateUserCallback = { result ->
188
- handleOnrampAuthenticationResult(result, authenticateUserPromise!!)
189
- },
190
- verifyIdentityCallback = { result ->
191
- handleOnrampIdentityVerificationResult(result, identityVerificationPromise!!)
192
- },
193
- collectPaymentCallback = { result ->
194
- handleOnrampCollectPaymentResult(result, collectPaymentPromise!!)
195
- },
196
- authorizeCallback = { result ->
197
- handleOnrampAuthorizationResult(result, authorizePromise!!)
198
- },
199
- checkoutCallback = { result ->
200
- handleOnrampCheckoutResult(result, checkoutPromise!!)
201
- },
202
- verifyKycCallback = { result ->
203
- handleOnrampKycVerificationResult(result, verifyKycPromise!!)
204
- },
205
- )
206
-
207
190
  try {
208
- onrampPresenter = onrampCoordinator!!.createPresenter(activity, onrampCallbacks)
191
+ onrampPresenter = onrampCoordinator!!.createPresenter(activity)
209
192
  promise.resolveVoid()
210
193
  } catch (e: Exception) {
211
194
  promise.resolve(createFailedError(e))
@@ -394,7 +377,7 @@ class OnrampSdkModule(
394
377
  }
395
378
  CoroutineScope(Dispatchers.IO).launch {
396
379
  when (val result = coordinator.updatePhoneNumber(phone)) {
397
- OnrampUpdatePhoneNumberResult.Completed -> {
380
+ is OnrampUpdatePhoneNumberResult.Completed -> {
398
381
  promise.resolveVoid()
399
382
  }
400
383
  is OnrampUpdatePhoneNumberResult.Failed -> {
@@ -404,19 +387,6 @@ class OnrampSdkModule(
404
387
  }
405
388
  }
406
389
 
407
- @ReactMethod
408
- override fun authenticateUser(promise: Promise) {
409
- val presenter =
410
- onrampPresenter ?: run {
411
- promise.resolve(createOnrampNotConfiguredError())
412
- return
413
- }
414
-
415
- authenticateUserPromise = promise
416
-
417
- presenter.authenticateUser()
418
- }
419
-
420
390
  @ReactMethod
421
391
  override fun verifyIdentity(promise: Promise) {
422
392
  val presenter =
@@ -461,8 +431,32 @@ class OnrampSdkModule(
461
431
 
462
432
  val method =
463
433
  when (paymentMethod) {
464
- "Card" -> PaymentMethodType.Card
465
- "BankAccount" -> PaymentMethodType.BankAccount
434
+ "Card" -> PaymentMethodSelection.Card()
435
+ "BankAccount" -> PaymentMethodSelection.BankAccount()
436
+ "CardAndBankAccount" -> PaymentMethodSelection.CardAndBankAccount()
437
+ "PlatformPay" -> {
438
+ val googlePayParams =
439
+ platformPayParams.getMap("googlePay")
440
+ ?: run {
441
+ promise.resolve(
442
+ createFailedError(
443
+ IllegalArgumentException("Missing googlePay params in platformPayParams"),
444
+ ),
445
+ )
446
+ return
447
+ }
448
+ val currencyCode = googlePayParams.getString("currencyCode") ?: ""
449
+ val amount = googlePayParams.getDouble("amount").toLong()
450
+ val transactionId = googlePayParams.getString("transactionId")
451
+ val label = googlePayParams.getString("label")
452
+
453
+ PaymentMethodSelection.GooglePay(
454
+ currencyCode = currencyCode,
455
+ amount = amount,
456
+ transactionId = transactionId,
457
+ label = label,
458
+ )
459
+ }
466
460
  else -> {
467
461
  promise.resolve(
468
462
  createFailedError(
@@ -505,20 +499,9 @@ class OnrampSdkModule(
505
499
  return
506
500
  }
507
501
 
508
- val checkoutHandler: suspend () -> String = {
509
- checkoutClientSecretDeferred = CompletableDeferred()
510
-
511
- val params = Arguments.createMap()
512
- params.putString("onrampSessionId", onrampSessionId)
513
-
514
- emitOnCheckoutClientSecretRequested(params)
515
-
516
- checkoutClientSecretDeferred!!.await()
517
- }
518
-
519
502
  checkoutPromise = promise
520
503
 
521
- presenter.performCheckout(onrampSessionId, checkoutHandler)
504
+ presenter.performCheckout(onrampSessionId)
522
505
  }
523
506
 
524
507
  @ReactMethod
@@ -579,6 +562,7 @@ class OnrampSdkModule(
579
562
  null
580
563
  }
581
564
  }
565
+
582
566
  token.hasKey("us_bank_account") -> {
583
567
  val bankMap = token.getMap("us_bank_account")
584
568
  if (bankMap != null) {
@@ -597,6 +581,7 @@ class OnrampSdkModule(
597
581
  null
598
582
  }
599
583
  }
584
+
600
585
  else -> null
601
586
  }
602
587
 
@@ -608,19 +593,41 @@ class OnrampSdkModule(
608
593
  )
609
594
  return
610
595
  }
596
+ rnScope.launch {
597
+ val iconDataUri: String =
598
+ try {
599
+ val base64 =
600
+ withContext(Dispatchers.Default) {
601
+ val drawable =
602
+ withTimeout(5_000L) {
603
+ withContext(Dispatchers.IO) {
604
+ paymentDetails.imageLoader()
605
+ }
606
+ }
607
+
608
+ getBitmapFromDrawable(drawable)?.let { bitmap ->
609
+ getBase64FromBitmap(bitmap)
610
+ } ?: ""
611
+ }
612
+
613
+ if (base64.isNotEmpty()) "data:image/png;base64,$base64" else ""
614
+ } catch (_: Exception) {
615
+ ""
616
+ }
611
617
 
612
- val icon =
613
- reactApplicationContext.currentActivity
614
- ?.let { ContextCompat.getDrawable(it, paymentDetails.iconRes) }
615
- ?.let { "data:image/png;base64," + getBase64FromBitmap(getBitmapFromDrawable(it)) }
616
-
617
- val displayData = Arguments.createMap()
618
+ val displayData = Arguments.createMap()
619
+ displayData.putString("icon", iconDataUri)
620
+ displayData.putString("label", paymentDetails.label)
621
+ displayData.putString("sublabel", paymentDetails.sublabel)
618
622
 
619
- displayData.putString("icon", icon)
620
- displayData.putString("label", paymentDetails.label)
621
- displayData.putString("sublabel", paymentDetails.sublabel)
623
+ if (token.hasKey("card")) {
624
+ displayData.putString("type", "Card")
625
+ } else if (token.hasKey("us_bank_account")) {
626
+ displayData.putString("type", "BankAccount")
627
+ }
622
628
 
623
- promise.resolve(createResult("displayData", displayData))
629
+ promise.resolve(createResult("displayData", displayData))
630
+ }
624
631
  }
625
632
 
626
633
  @ReactMethod
@@ -659,95 +666,6 @@ class OnrampSdkModule(
659
666
  }
660
667
  }
661
668
 
662
- private fun mapAppearance(appearanceMap: ReadableMap): LinkAppearance {
663
- val lightColorsMap = appearanceMap.getMap("lightColors")
664
- val darkColorsMap = appearanceMap.getMap("darkColors")
665
- val styleStr = appearanceMap.getString("style")
666
- val primaryButtonMap = appearanceMap.getMap("primaryButton")
667
-
668
- val lightColors =
669
- if (lightColorsMap != null) {
670
- val primaryColorStr = lightColorsMap.getString("primary")
671
- val contentColorStr = lightColorsMap.getString("contentOnPrimary")
672
- val borderSelectedColorStr = lightColorsMap.getString("borderSelected")
673
-
674
- Colors(
675
- primary = Color(android.graphics.Color.parseColor(primaryColorStr)),
676
- contentOnPrimary = Color(android.graphics.Color.parseColor(contentColorStr)),
677
- borderSelected = Color(android.graphics.Color.parseColor(borderSelectedColorStr)),
678
- )
679
- } else {
680
- null
681
- }
682
-
683
- val darkColors =
684
- if (darkColorsMap != null) {
685
- val primaryColorStr = darkColorsMap.getString("primary")
686
- val contentColorStr = darkColorsMap.getString("contentOnPrimary")
687
- val borderSelectedColorStr = darkColorsMap.getString("borderSelected")
688
-
689
- Colors(
690
- primary = Color(android.graphics.Color.parseColor(primaryColorStr)),
691
- contentOnPrimary = Color(android.graphics.Color.parseColor(contentColorStr)),
692
- borderSelected = Color(android.graphics.Color.parseColor(borderSelectedColorStr)),
693
- )
694
- } else {
695
- null
696
- }
697
-
698
- val style =
699
- when (styleStr) {
700
- "ALWAYS_LIGHT" -> Style.ALWAYS_LIGHT
701
- "ALWAYS_DARK" -> Style.ALWAYS_DARK
702
- else -> Style.AUTOMATIC
703
- }
704
-
705
- val primaryButton =
706
- if (primaryButtonMap != null) {
707
- PrimaryButton(
708
- cornerRadiusDp =
709
- if (primaryButtonMap.hasKey("cornerRadius")) {
710
- primaryButtonMap.getDouble("cornerRadius").toFloat()
711
- } else {
712
- null
713
- },
714
- heightDp =
715
- if (primaryButtonMap.hasKey("height")) {
716
- primaryButtonMap.getDouble("height").toFloat()
717
- } else {
718
- null
719
- },
720
- )
721
- } else {
722
- null
723
- }
724
-
725
- val default = LinkAppearance(style = Style.AUTOMATIC)
726
- return LinkAppearance(
727
- lightColors = lightColors ?: default.lightColors,
728
- darkColors = darkColors ?: default.darkColors,
729
- style = style,
730
- primaryButton = primaryButton ?: default.primaryButton,
731
- )
732
- }
733
-
734
- private fun handleOnrampAuthenticationResult(
735
- result: OnrampAuthenticateResult,
736
- promise: Promise,
737
- ) {
738
- when (result) {
739
- is OnrampAuthenticateResult.Completed -> {
740
- promise.resolveString("customerId", result.customerId)
741
- }
742
- is OnrampAuthenticateResult.Cancelled -> {
743
- promise.resolve(createCanceledError("Authentication was cancelled"))
744
- }
745
- is OnrampAuthenticateResult.Failed -> {
746
- promise.resolve(createFailedError(result.error))
747
- }
748
- }
749
- }
750
-
751
669
  private fun handleOnrampIdentityVerificationResult(
752
670
  result: OnrampVerifyIdentityResult,
753
671
  promise: Promise,
@@ -795,19 +713,42 @@ class OnrampSdkModule(
795
713
  ) {
796
714
  when (result) {
797
715
  is OnrampCollectPaymentMethodResult.Completed -> {
798
- val displayData = Arguments.createMap()
799
- val icon =
800
- reactApplicationContext.currentActivity
801
- ?.let { ContextCompat.getDrawable(it, result.displayData.iconRes) }
802
- ?.let { "data:image/png;base64," + getBase64FromBitmap(getBitmapFromDrawable(it)) }
803
- displayData.putString("icon", icon)
804
- displayData.putString("label", result.displayData.label)
805
- result.displayData.sublabel?.let { displayData.putString("sublabel", it) }
806
- promise.resolve(createResult("displayData", displayData))
716
+ rnScope.launch {
717
+ val iconDataUri =
718
+ try {
719
+ val base64 =
720
+ withContext(Dispatchers.Default) {
721
+ val drawable =
722
+ withTimeout(5_000L) {
723
+ withContext(Dispatchers.IO) {
724
+ result.displayData.imageLoader()
725
+ }
726
+ }
727
+
728
+ getBitmapFromDrawable(drawable)?.let { bitmap ->
729
+ getBase64FromBitmap(bitmap)
730
+ } ?: ""
731
+ }
732
+
733
+ if (base64.isNotEmpty()) "data:image/png;base64,$base64" else ""
734
+ } catch (_: Exception) {
735
+ ""
736
+ }
737
+
738
+ val displayData = Arguments.createMap()
739
+ displayData.putString("icon", iconDataUri)
740
+ displayData.putString("label", result.displayData.label)
741
+ result.displayData.sublabel?.let { displayData.putString("sublabel", it) }
742
+ displayData.putString("type", mapPaymentDetailsType(result.displayData.type))
743
+
744
+ promise.resolve(createResult("displayData", displayData))
745
+ }
807
746
  }
747
+
808
748
  is OnrampCollectPaymentMethodResult.Cancelled -> {
809
749
  promise.resolve(createCanceledError("Payment collection was cancelled"))
810
750
  }
751
+
811
752
  is OnrampCollectPaymentMethodResult.Failed -> {
812
753
  promise.resolve(createFailedError(result.error))
813
754
  }
@@ -3,6 +3,7 @@ package com.reactnativestripesdk
3
3
  import com.reactnativestripesdk.utils.PaymentSheetException
4
4
  import com.reactnativestripesdk.utils.readableArrayOf
5
5
  import com.reactnativestripesdk.utils.readableMapOf
6
+ import com.stripe.android.model.PaymentMethod
6
7
  import com.stripe.android.paymentelement.PaymentMethodOptionsSetupFutureUsagePreview
7
8
  import com.stripe.android.paymentsheet.CardFundingFilteringPrivatePreview
8
9
  import com.stripe.android.paymentsheet.PaymentSheet
@@ -1098,6 +1099,77 @@ class PaymentElementConfigTest {
1098
1099
  assertNull(result)
1099
1100
  }
1100
1101
 
1102
+ // ============================================
1103
+ // mapToTermsDisplay Tests
1104
+ // ============================================
1105
+
1106
+ @Test
1107
+ fun mapToTermsDisplay_NullParams_ReturnsNull() {
1108
+ val result = mapToTermsDisplay(null)
1109
+ assertNull(result)
1110
+ }
1111
+
1112
+ @Test
1113
+ fun mapToTermsDisplay_NoTermsDisplayKey_ReturnsNull() {
1114
+ val params = readableMapOf("someOtherKey" to "value")
1115
+ val result = mapToTermsDisplay(params)
1116
+ assertNull(result)
1117
+ }
1118
+
1119
+ @Test
1120
+ fun mapToTermsDisplay_CardNever_ReturnsSingleEntry() {
1121
+ val params =
1122
+ readableMapOf(
1123
+ "termsDisplay" to readableMapOf("card" to "never"),
1124
+ )
1125
+ val result = mapToTermsDisplay(params)
1126
+ assertNotNull(result)
1127
+ assertEquals(1, result!!.size)
1128
+ assertEquals(PaymentSheet.TermsDisplay.NEVER, result[PaymentMethod.Type.Card])
1129
+ }
1130
+
1131
+ @Test
1132
+ fun mapToTermsDisplay_CardAutomatic_ReturnsSingleEntry() {
1133
+ val params =
1134
+ readableMapOf(
1135
+ "termsDisplay" to readableMapOf("card" to "automatic"),
1136
+ )
1137
+ val result = mapToTermsDisplay(params)
1138
+ assertNotNull(result)
1139
+ assertEquals(1, result!!.size)
1140
+ assertEquals(PaymentSheet.TermsDisplay.AUTOMATIC, result[PaymentMethod.Type.Card])
1141
+ }
1142
+
1143
+ @Test
1144
+ fun mapToTermsDisplay_InvalidValue_Skipped() {
1145
+ val params =
1146
+ readableMapOf(
1147
+ "termsDisplay" to readableMapOf("card" to "invalid"),
1148
+ )
1149
+ val result = mapToTermsDisplay(params)
1150
+ assertNull(result)
1151
+ }
1152
+
1153
+ @Test
1154
+ fun mapToTermsDisplay_InvalidPaymentMethodType_Skipped() {
1155
+ val params =
1156
+ readableMapOf(
1157
+ "termsDisplay" to readableMapOf("foobar" to "never"),
1158
+ )
1159
+ val result = mapToTermsDisplay(params)
1160
+ assertNull(result)
1161
+ }
1162
+
1163
+ @Test
1164
+ fun mapToTermsDisplay_EmptyMap_ReturnsNull() {
1165
+ val params =
1166
+ readableMapOf(
1167
+ "termsDisplay" to readableMapOf(),
1168
+ )
1169
+ val result = mapToTermsDisplay(params)
1170
+ assertNull(result)
1171
+ }
1172
+
1101
1173
  @Test
1102
1174
  fun mapToAllowedCardFundingTypes_MissingAllowedCardFundingTypes_ReturnsNull() {
1103
1175
  val params =
@@ -365,7 +365,7 @@ class PaymentMethodMessagingElementConfigTest {
365
365
  val colors =
366
366
  PaymentMethodMessagingElement.Appearance
367
367
  .Colors()
368
- .infoIconColor("#0000FF".toColorInt())
368
+ .linkTextColor("#0000FF".toColorInt())
369
369
  colors(colors)
370
370
  }
371
371
 
@@ -391,7 +391,7 @@ class PaymentMethodMessagingElementConfigTest {
391
391
  val colors =
392
392
  PaymentMethodMessagingElement.Appearance
393
393
  .Colors()
394
- .infoIconColor("#0000FF".toColorInt())
394
+ .linkTextColor("#0000FF".toColorInt())
395
395
  colors(colors)
396
396
  }
397
397
 
@@ -526,7 +526,7 @@ class PaymentMethodMessagingElementConfigTest {
526
526
  expected: Any,
527
527
  actual: Any,
528
528
  ) {
529
- val fieldNames = listOf("textColor", "infoIconColor")
529
+ val fieldNames = listOf("textColor", "linkTextColor")
530
530
 
531
531
  for (fieldName in fieldNames) {
532
532
  val expectedField = expected.javaClass.getDeclaredField(fieldName)