@stripe/stripe-react-native 0.30.0 → 0.31.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/android/gradle.properties +1 -1
  3. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +41 -10
  4. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +10 -3
  5. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +129 -82
  6. package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt +329 -0
  7. package/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerAdapter.kt +138 -0
  8. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +8 -2
  9. package/ios/CustomerSheet/CustomerSheetUtils.swift +181 -0
  10. package/ios/CustomerSheet/ReactNativeCustomerAdapter.swift +173 -0
  11. package/ios/Mappers.swift +1 -1
  12. package/ios/StripeSdk+CustomerSheet.swift +166 -0
  13. package/ios/StripeSdk+PaymentSheet.swift +2 -2
  14. package/ios/StripeSdk.m +53 -0
  15. package/ios/StripeSdk.swift +14 -1
  16. package/jest/mock.js +0 -37
  17. package/lib/commonjs/NativeStripeSdk.js.map +1 -1
  18. package/lib/commonjs/components/CustomerSheet.js +2 -0
  19. package/lib/commonjs/components/CustomerSheet.js.map +1 -0
  20. package/lib/commonjs/functions.js +1 -1
  21. package/lib/commonjs/functions.js.map +1 -1
  22. package/lib/commonjs/index.js +1 -1
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/types/CustomerSheet.js +2 -0
  25. package/lib/commonjs/types/CustomerSheet.js.map +1 -0
  26. package/lib/commonjs/types/Errors.js +1 -1
  27. package/lib/commonjs/types/Errors.js.map +1 -1
  28. package/lib/commonjs/types/index.js +1 -1
  29. package/lib/commonjs/types/index.js.map +1 -1
  30. package/lib/module/NativeStripeSdk.js.map +1 -1
  31. package/lib/module/components/CustomerSheet.js +2 -0
  32. package/lib/module/components/CustomerSheet.js.map +1 -0
  33. package/lib/module/functions.js +1 -1
  34. package/lib/module/functions.js.map +1 -1
  35. package/lib/module/index.js +1 -1
  36. package/lib/module/index.js.map +1 -1
  37. package/lib/module/types/CustomerSheet.js +2 -0
  38. package/lib/module/types/CustomerSheet.js.map +1 -0
  39. package/lib/module/types/Errors.js +1 -1
  40. package/lib/module/types/Errors.js.map +1 -1
  41. package/lib/module/types/index.js +1 -1
  42. package/lib/module/types/index.js.map +1 -1
  43. package/lib/typescript/src/NativeStripeSdk.d.ts +14 -1
  44. package/lib/typescript/src/components/CustomerSheet.d.ts +59 -0
  45. package/lib/typescript/src/index.d.ts +2 -0
  46. package/lib/typescript/src/types/CustomerSheet.d.ts +94 -0
  47. package/lib/typescript/src/types/Errors.d.ts +4 -0
  48. package/lib/typescript/src/types/index.d.ts +1 -0
  49. package/package.json +1 -1
  50. package/src/NativeStripeSdk.tsx +31 -0
  51. package/src/components/CustomerSheet.tsx +327 -0
  52. package/src/functions.ts +5 -0
  53. package/src/index.tsx +3 -0
  54. package/src/types/CustomerSheet.ts +111 -0
  55. package/src/types/Errors.ts +5 -0
  56. package/src/types/index.ts +1 -0
  57. package/stripe-react-native.podspec +1 -1
  58. package/android/src/main/java/com/reactnativestripesdk/GooglePayFragment.kt +0 -211
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.31.0 - 2023-09-08
6
+
7
+ **Features**
8
+
9
+ - **[BETA]** Added [CustomerSheet](https://stripe.com/docs/elements/customer-sheet?platform=react-native) API, a prebuilt UI component that lets your customers manage their saved payment methods. [#1491](https://github.com/stripe/stripe-react-native/pull/1491)
10
+ - [PaymentSheet] Added support for AmazonPay (private beta), BLIK (iOS only), GrabPay, and FPX with PaymentIntents. [#1491](https://github.com/stripe/stripe-react-native/pull/1491)
11
+
12
+ **Fixes**
13
+
14
+ - Fixed font scaling on Android PaymentSheet not respecting floating-point number values. [#1469](https://github.com/stripe/stripe-react-native/pull/1469)
15
+
5
16
  ## 0.30.0 - 2023-08-04
6
17
 
7
18
  **Features**
@@ -1,3 +1,3 @@
1
1
  StripeSdk_kotlinVersion=1.8.0
2
2
  # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
3
- StripeSdk_stripeVersion=20.28.+
3
+ StripeSdk_stripeVersion=20.29.+
@@ -22,9 +22,11 @@ fun buildPaymentSheetAppearance(userParams: Bundle?, context: Context): PaymentS
22
22
  }
23
23
 
24
24
  private fun buildTypography(fontParams: Bundle?, context: Context): PaymentSheet.Typography {
25
+ val scale = getDoubleOrNull(fontParams, PaymentSheetAppearanceKeys.SCALE)
26
+ val resId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, PaymentSheet.Typography.default.fontResId, context)
25
27
  return PaymentSheet.Typography.default.copy(
26
- sizeScaleFactor = getFloatOr(fontParams, PaymentSheetAppearanceKeys.SCALE, PaymentSheet.Typography.default.sizeScaleFactor),
27
- fontResId = getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, PaymentSheet.Typography.default.fontResId, context)
28
+ sizeScaleFactor = scale?.toFloat() ?: PaymentSheet.Typography.default.sizeScaleFactor,
29
+ fontResId = resId
28
30
  )
29
31
  }
30
32
 
@@ -105,20 +107,49 @@ private fun buildPrimaryButtonColors(colorParams: Bundle, default: PaymentSheet.
105
107
  )
106
108
  }
107
109
 
110
+ private fun getDoubleOrNull(bundle: Bundle?, key: String): Double? {
111
+ if (bundle?.containsKey(key) == true) {
112
+ val valueOfUnknownType = bundle.get(key)
113
+ if (valueOfUnknownType is Double) {
114
+ return valueOfUnknownType
115
+ } else if (valueOfUnknownType is Int) {
116
+ return valueOfUnknownType.toDouble()
117
+ } else if (valueOfUnknownType is Float) {
118
+ return valueOfUnknownType.toDouble()
119
+ }
120
+ }
121
+
122
+ return null
123
+ }
124
+
108
125
  private fun getFloatOr(bundle: Bundle?, key: String, defaultValue: Float): Float {
109
- return if (bundle?.containsKey(key) == true) {
110
- bundle.getFloat(key, bundle.getInt(key).toFloat())
111
- } else {
112
- defaultValue
126
+ if (bundle?.containsKey(key) == true) {
127
+ val valueOfUnknownType = bundle.get(key)
128
+ if (valueOfUnknownType is Float) {
129
+ return valueOfUnknownType
130
+ } else if (valueOfUnknownType is Int) {
131
+ return valueOfUnknownType.toFloat()
132
+ } else if (valueOfUnknownType is Double) {
133
+ return valueOfUnknownType.toFloat()
134
+ }
113
135
  }
136
+
137
+ return defaultValue
114
138
  }
115
139
 
116
140
  private fun getFloatOrNull(bundle: Bundle?, key: String): Float? {
117
- return if (bundle?.containsKey(key) == true) {
118
- bundle.getFloat(key, bundle.getInt(key).toFloat())
119
- } else {
120
- null
141
+ if (bundle?.containsKey(key) == true) {
142
+ val valueOfUnknownType = bundle.get(key)
143
+ if (valueOfUnknownType is Float) {
144
+ return valueOfUnknownType
145
+ } else if (valueOfUnknownType is Int) {
146
+ return valueOfUnknownType.toFloat()
147
+ } else if (valueOfUnknownType is Double) {
148
+ return valueOfUnknownType.toFloat()
149
+ }
121
150
  }
151
+
152
+ return null
122
153
  }
123
154
 
124
155
  @Throws(PaymentSheetAppearanceException::class)
@@ -6,6 +6,7 @@ import android.content.Context
6
6
  import android.graphics.Bitmap
7
7
  import android.graphics.Canvas
8
8
  import android.graphics.Color
9
+ import android.graphics.drawable.Drawable
9
10
  import android.os.Bundle
10
11
  import android.os.Handler
11
12
  import android.os.Looper
@@ -399,10 +400,16 @@ class PaymentSheetFragment(
399
400
  }
400
401
 
401
402
  fun getBitmapFromVectorDrawable(context: Context?, drawableId: Int): Bitmap? {
402
- var drawable = AppCompatResources.getDrawable(context!!, drawableId) ?: return null
403
+ val drawable = AppCompatResources.getDrawable(context!!, drawableId) ?: return null
404
+ return getBitmapFromDrawable(drawable)
405
+ }
403
406
 
404
- drawable = DrawableCompat.wrap(drawable).mutate()
405
- val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
407
+ fun getBitmapFromDrawable(drawable: Drawable): Bitmap? {
408
+ val drawableCompat = DrawableCompat.wrap(drawable).mutate()
409
+ if (drawableCompat.intrinsicWidth <= 0 || drawableCompat.intrinsicHeight <= 0) {
410
+ return null
411
+ }
412
+ val bitmap = Bitmap.createBitmap(drawableCompat.intrinsicWidth, drawableCompat.intrinsicHeight, Bitmap.Config.ARGB_8888)
406
413
  bitmap.eraseColor(Color.WHITE)
407
414
  val canvas = Canvas(bitmap)
408
415
  drawable.setBounds(0, 0, canvas.width, canvas.height)
@@ -22,6 +22,7 @@ import com.stripe.android.view.AddPaymentMethodActivityStarter
22
22
  import kotlinx.coroutines.CoroutineScope
23
23
  import kotlinx.coroutines.Dispatchers
24
24
  import kotlinx.coroutines.launch
25
+ import org.json.JSONObject
25
26
 
26
27
 
27
28
  @ReactModule(name = StripeSdkModule.NAME)
@@ -44,10 +45,11 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
44
45
  private var platformPayUsesDeprecatedTokenFlow = false
45
46
 
46
47
  private var paymentSheetFragment: PaymentSheetFragment? = null
47
- private var googlePayFragment: GooglePayFragment? = null
48
48
  private var paymentLauncherFragment: PaymentLauncherFragment? = null
49
49
  private var collectBankAccountLauncherFragment: CollectBankAccountLauncherFragment? = null
50
50
 
51
+ private var customerSheetFragment: CustomerSheetFragment? = null
52
+
51
53
  internal var eventListenerCount = 0
52
54
 
53
55
  // If you create a new Fragment, you must put the tag here, otherwise result callbacks for that
@@ -55,12 +57,12 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
55
57
  private val allStripeFragmentTags: List<String>
56
58
  get() = listOf(
57
59
  PaymentSheetFragment.TAG,
58
- GooglePayFragment.TAG,
59
60
  PaymentLauncherFragment.TAG,
60
61
  CollectBankAccountLauncherFragment.TAG,
61
62
  FinancialConnectionsSheetFragment.TAG,
62
63
  AddressLauncherFragment.TAG,
63
- GooglePayLauncherFragment.TAG
64
+ GooglePayLauncherFragment.TAG,
65
+ CustomerSheetFragment.TAG
64
66
  )
65
67
 
66
68
  private val mActivityEventListener = object : BaseActivityEventListener() {
@@ -503,11 +505,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
503
505
  fun retrievePaymentIntent(clientSecret: String, promise: Promise) {
504
506
  CoroutineScope(Dispatchers.IO).launch {
505
507
  val paymentIntent = stripe.retrievePaymentIntentSynchronous(clientSecret)
506
- paymentIntent?.let {
507
- promise.resolve(createResult("paymentIntent", mapFromPaymentIntentResult(it)))
508
- } ?: run {
509
- promise.resolve(createError(RetrievePaymentIntentErrorType.Unknown.toString(), "Failed to retrieve the PaymentIntent"))
510
- }
508
+ promise.resolve(createResult("paymentIntent", mapFromPaymentIntentResult(paymentIntent)))
511
509
  }
512
510
  }
513
511
 
@@ -515,11 +513,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
515
513
  fun retrieveSetupIntent(clientSecret: String, promise: Promise) {
516
514
  CoroutineScope(Dispatchers.IO).launch {
517
515
  val setupIntent = stripe.retrieveSetupIntentSynchronous(clientSecret)
518
- setupIntent?.let {
519
- promise.resolve(createResult("setupIntent", mapFromSetupIntentResult(it)))
520
- } ?: run {
521
- promise.resolve(createError(RetrieveSetupIntentErrorType.Unknown.toString(), "Failed to retrieve the SetupIntent"))
522
- }
516
+ promise.resolve(createResult("setupIntent", mapFromSetupIntentResult(setupIntent)))
523
517
  }
524
518
  }
525
519
 
@@ -572,62 +566,6 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
572
566
  }
573
567
  }
574
568
 
575
- @ReactMethod
576
- fun isGooglePaySupported(params: ReadableMap?, promise: Promise) {
577
- val fragment = GooglePayPaymentMethodLauncherFragment(
578
- reactApplicationContext,
579
- getBooleanOrFalse(params, "testEnv"),
580
- getBooleanOrFalse(params, "existingPaymentMethodRequired"),
581
- promise
582
- )
583
-
584
- getCurrentActivityOrResolveWithError(promise)?.let {
585
- try {
586
- it.supportFragmentManager.beginTransaction()
587
- .add(fragment, GooglePayPaymentMethodLauncherFragment.TAG)
588
- .commit()
589
- } catch (error: IllegalStateException) {
590
- promise.resolve(createError(ErrorType.Failed.toString(), error.message))
591
- }
592
- }
593
- }
594
-
595
- @ReactMethod
596
- fun initGooglePay(params: ReadableMap, promise: Promise) {
597
- googlePayFragment = GooglePayFragment(promise).also {
598
- val bundle = toBundleObject(params)
599
- it.arguments = bundle
600
- }
601
-
602
- getCurrentActivityOrResolveWithError(promise)?.let {
603
- try {
604
- it.supportFragmentManager.beginTransaction()
605
- .add(googlePayFragment!!, GooglePayFragment.TAG)
606
- .commit()
607
- } catch (error: IllegalStateException) {
608
- promise.resolve(createError(ErrorType.Failed.toString(), error.message))
609
- }
610
- }
611
- }
612
-
613
- @ReactMethod
614
- fun presentGooglePay(params: ReadableMap, promise: Promise) {
615
- val clientSecret = getValOr(params, "clientSecret") ?: run {
616
- promise.resolve(createError(GooglePayErrorType.Failed.toString(), "you must provide clientSecret"))
617
- return
618
- }
619
-
620
- if (getBooleanOrFalse(params, "forSetupIntent")) {
621
- val currencyCode = getValOr(params, "currencyCode") ?: run {
622
- promise.resolve(createError(GooglePayErrorType.Failed.toString(), "you must provide currencyCode"))
623
- return
624
- }
625
- googlePayFragment?.presentForSetupIntent(clientSecret, currencyCode, promise)
626
- } else {
627
- googlePayFragment?.presentForPaymentIntent(clientSecret, promise)
628
- }
629
- }
630
-
631
569
  @ReactMethod
632
570
  fun confirmPlatformPay(clientSecret: String, params: ReadableMap, isPaymentIntent: Boolean, promise: Promise) {
633
571
  if (!::stripe.isInitialized) {
@@ -684,19 +622,6 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
684
622
  }
685
623
  }
686
624
 
687
- @ReactMethod
688
- fun createGooglePayPaymentMethod(params: ReadableMap, promise: Promise) {
689
- val currencyCode = getValOr(params, "currencyCode", null) ?: run {
690
- promise.resolve(createError(GooglePayErrorType.Failed.toString(), "you must provide currencyCode"))
691
- return
692
- }
693
- val amount = getIntOrNull(params, "amount") ?: run {
694
- promise.resolve(createError(GooglePayErrorType.Failed.toString(), "you must provide amount"))
695
- return
696
- }
697
- googlePayFragment?.createPaymentMethod(currencyCode, amount, promise)
698
- }
699
-
700
625
  @ReactMethod
701
626
  fun createPlatformPayPaymentMethod(params: ReadableMap, usesDeprecatedTokenFlow: Boolean, promise: Promise) {
702
627
  val googlePayParams: ReadableMap = params.getMap("googlePay") ?: run {
@@ -891,6 +816,128 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
891
816
  }
892
817
  }
893
818
 
819
+ @ReactMethod
820
+ fun initCustomerSheet(params: ReadableMap, customerAdapterOverrides: ReadableMap, promise: Promise) {
821
+ if (!::stripe.isInitialized) {
822
+ promise.resolve(createMissingInitError())
823
+ return
824
+ }
825
+
826
+ getCurrentActivityOrResolveWithError(promise)?.let { activity ->
827
+ customerSheetFragment?.removeFragment(reactApplicationContext)
828
+ customerSheetFragment = CustomerSheetFragment().also {
829
+ it.context = reactApplicationContext
830
+ it.initPromise = promise
831
+ val bundle = toBundleObject(params)
832
+ bundle.putBundle("customerAdapter", toBundleObject(customerAdapterOverrides))
833
+ it.arguments = bundle
834
+ }
835
+ try {
836
+ activity.supportFragmentManager.beginTransaction()
837
+ .add(customerSheetFragment!!, CustomerSheetFragment.TAG)
838
+ .commit()
839
+ } catch (error: IllegalStateException) {
840
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
841
+ }
842
+ }
843
+ }
844
+
845
+ @ReactMethod
846
+ fun presentCustomerSheet(params: ReadableMap, promise: Promise) {
847
+ var timeout: Long? = null
848
+ if (params.hasKey("timeout")) {
849
+ timeout = params.getInt("timeout").toLong()
850
+ }
851
+ customerSheetFragment?.present(timeout, promise) ?: run {
852
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
853
+ }
854
+ }
855
+
856
+ @ReactMethod
857
+ fun retrieveCustomerSheetPaymentOptionSelection(promise: Promise) {
858
+ customerSheetFragment?.retrievePaymentOptionSelection(promise) ?: run {
859
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
860
+ }
861
+ }
862
+
863
+ @ReactMethod
864
+ fun customerAdapterFetchPaymentMethodsCallback(paymentMethodJsonObjects: ReadableArray, promise: Promise) {
865
+ customerSheetFragment?.let { fragment ->
866
+ val paymentMethods = mutableListOf<PaymentMethod>()
867
+ for (paymentMethodJson in paymentMethodJsonObjects.toArrayList()) {
868
+ PaymentMethod.fromJson(JSONObject((paymentMethodJson as HashMap<*, *>)))?.let {
869
+ paymentMethods.add(it)
870
+ } ?: run {
871
+ Log.e("StripeReactNative", "There was an error converting Payment Method JSON to a Stripe Payment Method")
872
+ }
873
+ }
874
+ fragment.customerAdapter?.fetchPaymentMethodsCallback?.complete(paymentMethods)
875
+ } ?: run {
876
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
877
+ return
878
+ }
879
+ }
880
+
881
+ @ReactMethod
882
+ fun customerAdapterAttachPaymentMethodCallback(paymentMethodJson: ReadableMap, promise: Promise) {
883
+ customerSheetFragment?.let {
884
+ val paymentMethod = PaymentMethod.fromJson(JSONObject(paymentMethodJson.toHashMap()))
885
+ if (paymentMethod == null) {
886
+ Log.e("StripeReactNative", "There was an error converting Payment Method JSON to a Stripe Payment Method")
887
+ return
888
+ }
889
+ it.customerAdapter?.attachPaymentMethodCallback?.complete(paymentMethod)
890
+ } ?: run {
891
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
892
+ return
893
+ }
894
+ }
895
+
896
+ @ReactMethod
897
+ fun customerAdapterDetachPaymentMethodCallback(paymentMethodJson: ReadableMap, promise: Promise) {
898
+ customerSheetFragment?.let {
899
+ val paymentMethod = PaymentMethod.fromJson(JSONObject(paymentMethodJson.toHashMap()))
900
+ if (paymentMethod == null) {
901
+ Log.e("StripeReactNative", "There was an error converting Payment Method JSON to a Stripe Payment Method")
902
+ return
903
+ }
904
+ it.customerAdapter?.detachPaymentMethodCallback?.complete(paymentMethod)
905
+ } ?: run {
906
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
907
+ return
908
+ }
909
+ }
910
+
911
+ @ReactMethod
912
+ fun customerAdapterSetSelectedPaymentOptionCallback(promise: Promise) {
913
+ customerSheetFragment?.let {
914
+ it.customerAdapter?.setSelectedPaymentOptionCallback?.complete(Unit)
915
+ } ?: run {
916
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
917
+ return
918
+ }
919
+ }
920
+
921
+ @ReactMethod
922
+ fun customerAdapterFetchSelectedPaymentOptionCallback(paymentOption: String?, promise: Promise) {
923
+ customerSheetFragment?.let {
924
+ it.customerAdapter?.fetchSelectedPaymentOptionCallback?.complete(paymentOption)
925
+ } ?: run {
926
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
927
+ return
928
+ }
929
+ }
930
+
931
+ @ReactMethod
932
+ fun customerAdapterSetupIntentClientSecretForCustomerAttachCallback(clientSecret: String, promise: Promise) {
933
+ customerSheetFragment?.let {
934
+ it.customerAdapter?.setupIntentClientSecretForCustomerAttachCallback?.complete(clientSecret)
935
+ } ?: run {
936
+ promise.resolve(CustomerSheetFragment.createMissingInitError())
937
+ return
938
+ }
939
+ }
940
+
894
941
  @ReactMethod
895
942
  fun addListener(eventName: String) {
896
943
  eventListenerCount++