@stripe/stripe-react-native 0.8.0 → 0.9.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 (56) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +2 -2
  3. package/android/src/main/java/com/reactnativestripesdk/CardChangedEvent.kt +1 -0
  4. package/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +3 -0
  5. package/android/src/main/java/com/reactnativestripesdk/CardFormCompleteEvent.kt +1 -0
  6. package/android/src/main/java/com/reactnativestripesdk/CardFormView.kt +1 -0
  7. package/android/src/main/java/com/reactnativestripesdk/CollectBankAccountLauncherFragment.kt +1 -1
  8. package/android/src/main/java/com/reactnativestripesdk/GooglePayPaymentMethodLauncherFragment.kt +1 -1
  9. package/android/src/main/java/com/reactnativestripesdk/Mappers.kt +22 -22
  10. package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +36 -5
  11. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +38 -15
  12. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonManager.kt +3 -8
  13. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt +6 -10
  14. package/ios/CardFieldView.swift +1 -0
  15. package/ios/CardFormView.swift +1 -0
  16. package/ios/Mappers.swift +2 -0
  17. package/ios/PaymentMethodFactory.swift +8 -0
  18. package/ios/StripeSdk.swift +5 -1
  19. package/ios/pushprovisioning/AddToWalletButtonManager.m +1 -4
  20. package/ios/pushprovisioning/AddToWalletButtonView.swift +12 -14
  21. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  22. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  23. package/lib/commonjs/components/CardField.js +1 -1
  24. package/lib/commonjs/components/CardField.js.map +1 -1
  25. package/lib/commonjs/components/CardForm.js +1 -1
  26. package/lib/commonjs/components/CardForm.js.map +1 -1
  27. package/lib/commonjs/components/StripeProvider.js +1 -1
  28. package/lib/commonjs/components/StripeProvider.js.map +1 -1
  29. package/lib/commonjs/types/SetupIntent.js.map +1 -1
  30. package/lib/commonjs/types/components/CardFieldInput.js.map +1 -1
  31. package/lib/module/components/AddToWalletButton.js +1 -1
  32. package/lib/module/components/AddToWalletButton.js.map +1 -1
  33. package/lib/module/components/CardField.js +1 -1
  34. package/lib/module/components/CardField.js.map +1 -1
  35. package/lib/module/components/CardForm.js +1 -1
  36. package/lib/module/components/CardForm.js.map +1 -1
  37. package/lib/module/components/StripeProvider.js +1 -1
  38. package/lib/module/components/StripeProvider.js.map +1 -1
  39. package/lib/module/types/SetupIntent.js.map +1 -1
  40. package/lib/module/types/components/CardFieldInput.js.map +1 -1
  41. package/lib/typescript/example/src/App.d.ts +1 -0
  42. package/lib/typescript/example/src/screens/PayPalScreen.d.ts +1 -0
  43. package/lib/typescript/src/components/AddToWalletButton.d.ts +18 -11
  44. package/lib/typescript/src/types/PaymentMethod.d.ts +8 -2
  45. package/lib/typescript/src/types/SetupIntent.d.ts +1 -1
  46. package/lib/typescript/src/types/components/CardFieldInput.d.ts +1 -0
  47. package/lib/typescript/src/types/components/CardFormView.d.ts +1 -0
  48. package/package.json +2 -2
  49. package/src/components/AddToWalletButton.tsx +18 -11
  50. package/src/components/CardField.tsx +2 -1
  51. package/src/components/CardForm.tsx +2 -1
  52. package/src/types/PaymentMethod.ts +10 -1
  53. package/src/types/SetupIntent.ts +18 -1
  54. package/src/types/components/CardFieldInput.ts +1 -0
  55. package/src/types/components/CardFormView.ts +1 -0
  56. package/stripe-react-native.podspec +3 -2
package/CHANGELOG.md CHANGED
@@ -1,7 +1,25 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.9.0
4
+
5
+ - [#913](https://github.com/stripe/stripe-react-native/pull/913) BREAKING CHANGE: Changed props for the `<AddToWalletButton />` component. Instead of passing `cardHolderName`, `cardLastFour`, `cardDescription`, and `cardBrand` directly as props, you will instead pass a `cardDetails` prop, which is an object containing the following fields:
6
+ - `primaryAccountIdentifier`: The `wallet.primary_account_identifier` value from the issued card.
7
+ - `name`: The card holder name (previously `cardHolderName`).
8
+ - `description`: A user-facing description of the card (previously `cardDescription`).
9
+ - `lastFour`: Last 4 digits of the card, optional (previously `cardLastFour`).
10
+ - `brand`: The card brand, optional (previously `cardBrand`).
11
+ - [#925](https://github.com/stripe/stripe-react-native/pull/925) Feat: `us_bank_account` payment method is now available in the payment sheet on iOS. (& Updated `stripe-ios` from 22.2.0 to 22.3.0)
12
+ - [#929](https://github.com/stripe/stripe-react-native/pull/929) Feat: added PayPal support (not currently supported for SetupIntents)
13
+ - [#928](https://github.com/stripe/stripe-react-native/pull/928) feat: expose 'cvc' when `dangerouslyGetCardDetails` is set to true
14
+ - [#931](https://github.com/stripe/stripe-react-native/pull/931) feat: add token & paymentMethodId handling to confirmPayment for Cards
15
+ - [#932](https://github.com/stripe/stripe-react-native/pull/932) fix: manually forward activity results to paymentLauncherFragment
16
+ - [#933](https://github.com/stripe/stripe-react-native/pull/933) fix: address "Can not perform this action after onSaveInstanceState" crashes on Android
17
+ - [#914](https://github.com/stripe/stripe-react-native/pull/914) fix: add `fingerprint` to Card result object on Android (already present on iOS)
18
+ - [#912](https://github.com/stripe/stripe-react-native/pull/912) fix: allow for providing zip code straight from `CardField` component on Android
19
+
3
20
  ## 0.8.0
4
21
 
22
+ - **Breaking: This version requires you use `react-native@0.64.0` or above**
5
23
  - [#902](https://github.com/stripe/stripe-react-native/pull/902) fix: create custom babel plugin for package.json imports in src/
6
24
  - [#889](https://github.com/stripe/stripe-react-native/pull/889) Feat: add support for push provisioning (adding cards to native wallets)
7
25
  - [#890](https://github.com/stripe/stripe-react-native/pull/890) BREAKING CHANGE: Changed parameters for: `createPaymentMethod`, `confirmPayment`, `confirmSetupIntent`, `collectBankAccountForPayment`, and `collectBankAccountForSetup`. Please read [this migration guide](./docs/upgrading-from-v0.7.0.md) for details.
package/README.md CHANGED
@@ -7,7 +7,7 @@ The Stripe React Native SDK allows you to build delightful payment experiences i
7
7
 
8
8
  ## Getting started
9
9
 
10
- Get started with our [📚 integration guides](https://stripe.com/docs/payments/accept-a-payment?platform=react-native) and [example project](#run-the-example-app), or [📘 browse the SDK reference](https://stripe.dev/stripe-react-native).
10
+ Get started with our [📚 integration guides](https://stripe.com/docs/payments/accept-a-payment?platform=react-native) and [example project](./CONTRIBUTING.md#running-the-example-app), or [📘 browse the SDK reference](https://stripe.dev/stripe-react-native).
11
11
 
12
12
  > Updating to a newer version of the SDK? See our [changelog](https://github.com/stripe/stripe-react-native/blob/master/CHANGELOG.md).
13
13
 
@@ -23,7 +23,7 @@ Get started with our [📚 integration guides](https://stripe.com/docs/payments/
23
23
 
24
24
  **Native UI**: We provide native screens and elements to securely collect payment details on Android and iOS.
25
25
 
26
- **PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay, and Sofort.
26
+ **PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay, Sofort, and ACH.
27
27
 
28
28
  #### Recommended usage
29
29
 
@@ -42,6 +42,7 @@ internal class CardChangedEvent constructor(viewTag: Int, private val cardDetail
42
42
 
43
43
  if (dangerouslyGetFullCardDetails) {
44
44
  eventData.putString("number", cardDetails["number"]?.toString()?.replace(" ", ""))
45
+ eventData.putString("cvc", cardDetails["cvc"]?.toString())
45
46
  }
46
47
 
47
48
  return eventData
@@ -286,6 +286,9 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) {
286
286
  override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
287
287
  override fun afterTextChanged(p0: Editable?) {}
288
288
  override fun onTextChanged(var1: CharSequence?, var2: Int, var3: Int, var4: Int) {
289
+ if (dangerouslyGetFullCardDetails) {
290
+ cardDetails["cvc"] = var1.toString()
291
+ }
289
292
  sendCardDetailsEvent()
290
293
  }
291
294
  })
@@ -30,6 +30,7 @@ internal class CardFormCompleteEvent constructor(viewTag: Int, private val cardD
30
30
 
31
31
  if (dangerouslyGetFullCardDetails) {
32
32
  eventData.putString("number", cardDetails["number"]?.toString()?.replace(" ", ""))
33
+ eventData.putString("cvc", cardDetails["cvc"]?.toString())
33
34
  }
34
35
 
35
36
  return eventData
@@ -202,6 +202,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) {
202
202
 
203
203
  if (dangerouslyGetFullCardDetails) {
204
204
  cardDetails["number"] = cardParamsMap["number"] as String
205
+ cardDetails["cvc"] = cardParamsMap["cvc"] as String
205
206
  }
206
207
 
207
208
  mEventDispatcher?.dispatchEvent(
@@ -78,7 +78,7 @@ class CollectBankAccountLauncherFragment(
78
78
  promise.resolve(createError(ErrorType.Failed.toString(), result.error))
79
79
  }
80
80
  }
81
- (context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
81
+ (context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commitAllowingStateLoss()
82
82
  }
83
83
  }
84
84
  }
@@ -37,7 +37,7 @@ class GooglePayPaymentMethodLauncherFragment(
37
37
  ),
38
38
  readyCallback = {
39
39
  promise.resolve(it)
40
- (context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commit()
40
+ (context.currentActivity as? AppCompatActivity)?.supportFragmentManager?.beginTransaction()?.remove(this)?.commitAllowingStateLoss()
41
41
  },
42
42
  resultCallback = {}
43
43
  )
@@ -107,6 +107,7 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String {
107
107
  PaymentMethod.Type.WeChatPay -> "WeChatPay"
108
108
  PaymentMethod.Type.Klarna -> "Klarna"
109
109
  PaymentMethod.Type.USBankAccount -> "USBankAccount"
110
+ PaymentMethod.Type.PayPal -> "PayPal"
110
111
  else -> "Unknown"
111
112
  }
112
113
  }
@@ -134,6 +135,7 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? {
134
135
  "WeChatPay" -> PaymentMethod.Type.WeChatPay
135
136
  "Klarna" -> PaymentMethod.Type.Klarna
136
137
  "USBankAccount" -> PaymentMethod.Type.USBankAccount
138
+ "PayPal" -> PaymentMethod.Type.PayPal
137
139
  else -> null
138
140
  }
139
141
  }
@@ -317,7 +319,6 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
317
319
 
318
320
  card.putString("brand", mapCardBrand(paymentMethod.card?.brand))
319
321
  card.putString("country", paymentMethod.card?.country)
320
-
321
322
  paymentMethod.card?.expiryYear?.let {
322
323
  card.putInt("expYear", it)
323
324
  }
@@ -326,6 +327,7 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
326
327
  }
327
328
  card.putString("funding", paymentMethod.card?.funding)
328
329
  card.putString("last4", paymentMethod.card?.last4)
330
+ card.putString("fingerprint", paymentMethod.card?.fingerprint)
329
331
 
330
332
  sepaDebit.putString("bankCode", paymentMethod.sepaDebit?.bankCode)
331
333
  sepaDebit.putString("country", paymentMethod.sepaDebit?.country)
@@ -504,24 +506,25 @@ fun getValOr(map: ReadableMap?, key: String, default: String? = ""): String? {
504
506
  } ?: default
505
507
  }
506
508
 
507
- internal fun mapToAddress(addressMap: ReadableMap?, cardAddress: Address?): Address? {
508
- if (addressMap == null) {
509
- return null
510
- }
509
+ internal fun mapToAddress(addressMap: ReadableMap?, cardAddress: Address?): Address {
511
510
  val address = Address.Builder()
512
- .setPostalCode(getValOr(addressMap, "postalCode"))
513
- .setCity(getValOr(addressMap, "city"))
514
- .setCountry(getValOr(addressMap, "country"))
515
- .setLine1(getValOr(addressMap, "line1"))
516
- .setLine2(getValOr(addressMap, "line2"))
517
- .setState(getValOr(addressMap, "state"))
518
-
519
- cardAddress?.let { ca ->
520
- ca.postalCode?.let {
521
- address.setPostalCode(it)
511
+
512
+ addressMap?.let {
513
+ address
514
+ .setPostalCode(getValOr(it, "postalCode"))
515
+ .setCity(getValOr(it, "city"))
516
+ .setCountry(getValOr(it, "country"))
517
+ .setLine1(getValOr(it, "line1"))
518
+ .setLine2(getValOr(it, "line2"))
519
+ .setState(getValOr(it, "state"))
520
+ }
521
+
522
+ cardAddress?.let {
523
+ if (!it.postalCode.isNullOrEmpty()) {
524
+ address.setPostalCode(it.postalCode)
522
525
  }
523
- ca.country?.let {
524
- address.setCountry(it)
526
+ if (!it.country.isNullOrEmpty()) {
527
+ address.setCountry(it.country)
525
528
  }
526
529
  }
527
530
 
@@ -532,19 +535,17 @@ internal fun mapToBillingDetails(billingDetails: ReadableMap?, cardAddress: Addr
532
535
  if (billingDetails == null && cardAddress == null) {
533
536
  return null
534
537
  }
535
- var address: Address? = null
538
+ val address = mapToAddress(getMapOrNull(billingDetails, "address"), cardAddress)
536
539
  val paymentMethodBillingDetailsBuilder = PaymentMethod.BillingDetails.Builder()
537
540
 
538
541
  if (billingDetails != null) {
539
- address = mapToAddress(getMapOrNull(billingDetails, "address"), cardAddress)
540
-
541
542
  paymentMethodBillingDetailsBuilder
542
543
  .setName(getValOr(billingDetails, "name"))
543
544
  .setPhone(getValOr(billingDetails, "phone"))
544
545
  .setEmail(getValOr(billingDetails, "email"))
545
546
  }
546
547
 
547
- paymentMethodBillingDetailsBuilder.setAddress(address ?: Address.Builder().build())
548
+ paymentMethodBillingDetailsBuilder.setAddress(address)
548
549
  return paymentMethodBillingDetailsBuilder.build()
549
550
  }
550
551
 
@@ -554,7 +555,6 @@ internal fun mapToShippingDetails(shippingDetails: ReadableMap?): ConfirmPayment
554
555
  }
555
556
 
556
557
  val address = mapToAddress(getMapOrNull(shippingDetails, "address"), null)
557
- ?: Address.Builder().build()
558
558
 
559
559
  return ConfirmPaymentIntentParams.Shipping(
560
560
  name = getValOr(shippingDetails, "name") ?: "",
@@ -32,6 +32,7 @@ class PaymentMethodCreateParamsFactory(
32
32
  PaymentMethod.Type.AuBecsDebit -> createAuBecsDebitPaymentConfirmParams()
33
33
  PaymentMethod.Type.Klarna -> createKlarnaPaymentConfirmParams()
34
34
  PaymentMethod.Type.USBankAccount -> createUSBankAccountPaymentConfirmParams()
35
+ PaymentMethod.Type.PayPal -> createPayPalPaymentConfirmParams()
35
36
  else -> {
36
37
  throw Exception("This paymentMethodType is not supported yet")
37
38
  }
@@ -52,6 +53,7 @@ class PaymentMethodCreateParamsFactory(
52
53
  PaymentMethod.Type.SepaDebit -> createSepaPaymentSetupParams()
53
54
  PaymentMethod.Type.AuBecsDebit -> createAuBecsDebitPaymentSetupParams()
54
55
  PaymentMethod.Type.USBankAccount -> createUSBankAccountPaymentSetupParams()
56
+ PaymentMethod.Type.PayPal -> createPayPalPaymentSetupParams()
55
57
  else -> {
56
58
  throw Exception("This paymentMethodType is not supported yet")
57
59
  }
@@ -172,14 +174,31 @@ class PaymentMethodCreateParamsFactory(
172
174
 
173
175
  @Throws(PaymentMethodCreateParamsException::class)
174
176
  private fun createCardPaymentSetupParams(): ConfirmSetupIntentParams {
177
+ val paymentMethodId = getValOr(paymentMethodData, "paymentMethodId", null)
178
+ val token = getValOr(paymentMethodData, "token", null)
175
179
  val cardParams = cardFieldView?.cardParams ?: cardFormView?.cardParams
176
- ?: throw PaymentMethodCreateParamsException("Card details not complete")
177
180
 
178
- val paymentMethodCreateParams =
179
- PaymentMethodCreateParams.create(cardParams, billingDetailsParams)
181
+ if (paymentMethodId != null) {
182
+ return ConfirmSetupIntentParams.create(
183
+ paymentMethodId,
184
+ clientSecret
185
+ )
186
+ }
180
187
 
181
- return ConfirmSetupIntentParams
182
- .create(paymentMethodCreateParams, clientSecret)
188
+ val paymentMethodCreateParams =
189
+ if (token != null)
190
+ PaymentMethodCreateParams.create(PaymentMethodCreateParams.Card.create(token), billingDetailsParams)
191
+ else if (cardParams != null)
192
+ PaymentMethodCreateParams.create(cardParams, billingDetailsParams)
193
+ else
194
+ null
195
+
196
+ if (paymentMethodCreateParams != null) {
197
+ return ConfirmSetupIntentParams
198
+ .create(paymentMethodCreateParams, clientSecret)
199
+ } else {
200
+ throw PaymentMethodCreateParamsException("Card details not complete")
201
+ }
183
202
  }
184
203
 
185
204
  @Throws(PaymentMethodCreateParamsException::class)
@@ -450,6 +469,10 @@ class PaymentMethodCreateParamsFactory(
450
469
  }
451
470
  }
452
471
 
472
+ @Throws(PaymentMethodCreateParamsException::class)
473
+ private fun createPayPalPaymentSetupParams(): ConfirmSetupIntentParams {
474
+ throw PaymentMethodCreateParamsException("PayPal is not yet supported through SetupIntents.")
475
+ }
453
476
 
454
477
  @Throws(PaymentMethodCreateParamsException::class)
455
478
  private fun createKlarnaPaymentConfirmParams(): ConfirmPaymentIntentParams {
@@ -492,6 +515,14 @@ class PaymentMethodCreateParamsFactory(
492
515
  }
493
516
  }
494
517
 
518
+ @Throws(PaymentMethodCreateParamsException::class)
519
+ private fun createPayPalPaymentConfirmParams(): ConfirmPaymentIntentParams {
520
+ return ConfirmPaymentIntentParams.createWithPaymentMethodCreateParams(
521
+ paymentMethodCreateParams = PaymentMethodCreateParams.createPayPal(null),
522
+ clientSecret = clientSecret,
523
+ )
524
+ }
525
+
495
526
  @Throws(PaymentMethodCreateParamsException::class)
496
527
  private fun createUSBankAccountParams(params: ReadableMap): PaymentMethodCreateParams {
497
528
  val accountNumber = getValOr(params, "accountNumber", null)
@@ -54,8 +54,11 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
54
54
  private val mActivityEventListener = object : BaseActivityEventListener() {
55
55
  override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
56
56
  if (::stripe.isInitialized) {
57
+ // BEGIN - Necessary on older versions of React Native (~0.64 and below)
57
58
  paymentSheetFragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
58
59
  googlePayFragment?.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
60
+ paymentLauncherFragment.activity?.activityResultRegistry?.dispatchResult(requestCode, resultCode, data)
61
+ // END
59
62
  try {
60
63
  val result = AddPaymentMethodActivityStarter.Result.fromIntent(data)
61
64
  if (data?.getParcelableExtra<Parcelable>("extra_activity_result") != null) {
@@ -225,9 +228,13 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
225
228
 
226
229
  paymentLauncherFragment = PaymentLauncherFragment(stripe, publishableKey, stripeAccountId)
227
230
  getCurrentActivityOrResolveWithError(promise)?.let {
228
- it.supportFragmentManager.beginTransaction()
229
- .add(paymentLauncherFragment, "payment_launcher_fragment")
230
- .commit()
231
+ try {
232
+ it.supportFragmentManager.beginTransaction()
233
+ .add(paymentLauncherFragment, "payment_launcher_fragment")
234
+ .commit()
235
+ } catch (error: IllegalStateException) {
236
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
237
+ }
231
238
 
232
239
  val localBroadcastManager = LocalBroadcastManager.getInstance(reactApplicationContext)
233
240
  localBroadcastManager.registerReceiver(mPaymentSheetReceiver, IntentFilter(ON_PAYMENT_RESULT_ACTION))
@@ -252,9 +259,13 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
252
259
  val bundle = toBundleObject(params)
253
260
  it.arguments = bundle
254
261
  }
255
- activity.supportFragmentManager.beginTransaction()
256
- .add(paymentSheetFragment!!, "payment_sheet_launch_fragment")
257
- .commit()
262
+ try {
263
+ activity.supportFragmentManager.beginTransaction()
264
+ .add(paymentSheetFragment!!, "payment_sheet_launch_fragment")
265
+ .commit()
266
+ } catch (error: IllegalStateException) {
267
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
268
+ }
258
269
  }
259
270
  }
260
271
 
@@ -562,9 +573,13 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
562
573
  )
563
574
 
564
575
  getCurrentActivityOrResolveWithError(promise)?.let {
565
- it.supportFragmentManager.beginTransaction()
566
- .add(fragment, "google_pay_support_fragment")
567
- .commit()
576
+ try {
577
+ it.supportFragmentManager.beginTransaction()
578
+ .add(fragment, "google_pay_support_fragment")
579
+ .commit()
580
+ } catch (error: IllegalStateException) {
581
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
582
+ }
568
583
  }
569
584
  }
570
585
 
@@ -578,9 +593,13 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
578
593
  getCurrentActivityOrResolveWithError(promise)?.let {
579
594
  initGooglePayPromise = promise
580
595
 
581
- it.supportFragmentManager.beginTransaction()
582
- .add(googlePayFragment!!, "google_pay_launch_fragment")
583
- .commit()
596
+ try {
597
+ it.supportFragmentManager.beginTransaction()
598
+ .add(googlePayFragment!!, "google_pay_launch_fragment")
599
+ .commit()
600
+ } catch (error: IllegalStateException) {
601
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
602
+ }
584
603
  }
585
604
  }
586
605
 
@@ -658,9 +677,13 @@ class StripeSdkModule(private val reactContext: ReactApplicationContext) : React
658
677
  promise
659
678
  )
660
679
  getCurrentActivityOrResolveWithError(promise)?.let {
661
- it.supportFragmentManager.beginTransaction()
662
- .add(fragment, "collect_bank_account_launcher_fragment")
663
- .commit()
680
+ try {
681
+ it.supportFragmentManager.beginTransaction()
682
+ .add(fragment, "collect_bank_account_launcher_fragment")
683
+ .commit()
684
+ } catch (error: IllegalStateException) {
685
+ promise.resolve(createError(ErrorType.Failed.toString(), error.message))
686
+ }
664
687
  }
665
688
  }
666
689
 
@@ -38,14 +38,9 @@ class AddToWalletButtonManager(applicationContext: ReactApplicationContext) : Si
38
38
  view.setSourceMap(source)
39
39
  }
40
40
 
41
- @ReactProp(name = "cardDescription")
42
- fun cardDescription(view: AddToWalletButtonView, cardDescription: String) {
43
- view.setCardDescription(cardDescription)
44
- }
45
-
46
- @ReactProp(name = "cardLastFour")
47
- fun cardLastFour(view: AddToWalletButtonView, last4: String) {
48
- view.setCardLastFour(last4)
41
+ @ReactProp(name = "cardDetails")
42
+ fun cardDetails(view: AddToWalletButtonView, cardDetails: ReadableMap) {
43
+ view.setCardDetails(cardDetails)
49
44
  }
50
45
 
51
46
  @ReactProp(name = "ephemeralKey")
@@ -22,8 +22,7 @@ import com.reactnativestripesdk.createError
22
22
 
23
23
 
24
24
  class AddToWalletButtonView(private val context: ThemedReactContext, private val requestManager: RequestManager) : AppCompatImageView(context) {
25
- private var cardDescription: String? = null
26
- private var cardLastFour: String? = null
25
+ private var cardDetails: ReadableMap? = null
27
26
  private var ephemeralKey: String? = null
28
27
  private var sourceMap: ReadableMap? = null
29
28
  private var token: ReadableMap? = null
@@ -35,7 +34,8 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val
35
34
 
36
35
  override fun performClick(): Boolean {
37
36
  super.performClick()
38
- cardDescription?.let { cardDescription ->
37
+
38
+ cardDetails?.getString("description")?.let { cardDescription ->
39
39
  ephemeralKey?.let { ephemeralKey ->
40
40
  PushProvisioningProxy.invoke(
41
41
  context.reactApplicationContext,
@@ -50,7 +50,7 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val
50
50
  }
51
51
  } ?: run {
52
52
  dispatchEvent(
53
- createError("Failed", "Missing parameters. `cardDescription` must be supplied in the props to <AddToWalletButton />")
53
+ createError("Failed", "Missing parameters. `cardDetails.cardDescription` must be supplied in the props to <AddToWalletButton />")
54
54
  )
55
55
  }
56
56
  return true
@@ -125,12 +125,8 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val
125
125
  sourceMap = map
126
126
  }
127
127
 
128
- fun setCardDescription(description: String) {
129
- cardDescription = description
130
- }
131
-
132
- fun setCardLastFour(last4: String) {
133
- cardLastFour = last4
128
+ fun setCardDetails(detailsMap: ReadableMap) {
129
+ cardDetails = detailsMap
134
130
  }
135
131
 
136
132
  fun setEphemeralKey(map: ReadableMap) {
@@ -145,6 +145,7 @@ class CardFieldView: UIView, STPPaymentCardTextFieldDelegate {
145
145
  }
146
146
  if (dangerouslyGetFullCardDetails) {
147
147
  cardData["number"] = textField.cardParams.number ?? ""
148
+ cardData["cvc"] = textField.cardParams.cvc ?? ""
148
149
  }
149
150
  onCardChange!(cardData as [AnyHashable : Any])
150
151
  }
@@ -52,6 +52,7 @@ class CardFormView: UIView, STPCardFormViewDelegate {
52
52
 
53
53
  if (dangerouslyGetFullCardDetails) {
54
54
  cardData["number"] = cardForm?.cardParams?.card?.number ?? ""
55
+ cardData["cvc"] = cardForm?.cardParams?.card?.cvc ?? ""
55
56
  }
56
57
  if (complete) {
57
58
  self.cardParams = cardForm?.cardParams?.card
package/ios/Mappers.swift CHANGED
@@ -283,6 +283,7 @@ class Mappers {
283
283
  case STPPaymentMethodType.afterpayClearpay: return "AfterpayClearpay"
284
284
  case STPPaymentMethodType.klarna: return "Klarna"
285
285
  case STPPaymentMethodType.USBankAccount: return "USBankAccount"
286
+ case STPPaymentMethodType.payPal: return "PayPal"
286
287
  case STPPaymentMethodType.unknown: return "Unknown"
287
288
  default: return "Unknown"
288
289
  }
@@ -311,6 +312,7 @@ class Mappers {
311
312
  case "Klarna": return STPPaymentMethodType.klarna
312
313
  case "WeChatPay": return STPPaymentMethodType.weChatPay
313
314
  case "USBankAccount": return STPPaymentMethodType.USBankAccount
315
+ case "PayPal": return STPPaymentMethodType.payPal
314
316
  default: return STPPaymentMethodType.unknown
315
317
  }
316
318
  }
@@ -51,6 +51,8 @@ class PaymentMethodFactory {
51
51
  return try createKlarnaPaymentMethodParams()
52
52
  case STPPaymentMethodType.USBankAccount:
53
53
  return try createUSBankAccountPaymentMethodParams()
54
+ case STPPaymentMethodType.payPal:
55
+ return try createPayPalPaymentMethodParams()
54
56
  // case STPPaymentMethodType.weChatPay:
55
57
  // return try createWeChatPayPaymentMethodParams()
56
58
  default:
@@ -98,6 +100,8 @@ class PaymentMethodFactory {
98
100
  return try createWeChatPayPaymentMethodOptions()
99
101
  case STPPaymentMethodType.USBankAccount:
100
102
  return try createUSBankAccountPaymentMethodOptions()
103
+ case STPPaymentMethodType.payPal:
104
+ return nil
101
105
  default:
102
106
  throw PaymentMethodError.paymentNotSupported
103
107
  }
@@ -353,6 +357,10 @@ class PaymentMethodFactory {
353
357
  throw PaymentMethodError.usBankAccountPaymentMissingParams
354
358
  }
355
359
  }
360
+
361
+ private func createPayPalPaymentMethodParams() throws -> STPPaymentMethodParams {
362
+ return STPPaymentMethodParams(payPal: STPPaymentMethodPayPalParams(), billingDetails: billingDetailsParams, metadata: nil)
363
+ }
356
364
  }
357
365
 
358
366
  enum PaymentMethodError: Error {
@@ -275,10 +275,14 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
275
275
  let paymentMethodData = params["paymentMethodData"] as? NSDictionary
276
276
  let type = Mappers.mapToPaymentMethodType(type: params["paymentMethodType"] as? String)
277
277
  guard let paymentMethodType = type else {
278
- resolve(Errors.createError(ErrorType.Failed, "You must provide paymentMethodType"))
278
+ resolve(Errors.createError(ErrorType.Failed, "You must provide paymentMethodType."))
279
279
  return
280
280
  }
281
281
 
282
+ if (paymentMethodType == .payPal) {
283
+ resolve(Errors.createError(ErrorType.Failed, "PayPal is not yet supported through SetupIntents."))
284
+ }
285
+
282
286
  var err: NSDictionary? = nil
283
287
  let setupIntentParams: STPSetupIntentConfirmParams = {
284
288
  // If payment method data is not supplied, assume payment method was attached through via collectBankAccount
@@ -12,10 +12,7 @@
12
12
  @interface RCT_EXTERN_MODULE(AddToWalletButtonManager, RCTViewManager)
13
13
  RCT_EXPORT_VIEW_PROPERTY(testEnv, BOOL)
14
14
  RCT_EXPORT_VIEW_PROPERTY(iOSButtonStyle, NSString)
15
- RCT_EXPORT_VIEW_PROPERTY(cardHolderName, NSString)
16
- RCT_EXPORT_VIEW_PROPERTY(cardDescription, NSString)
17
- RCT_EXPORT_VIEW_PROPERTY(cardLastFour, NSString)
18
- RCT_EXPORT_VIEW_PROPERTY(cardBrand, NSString)
15
+ RCT_EXPORT_VIEW_PROPERTY(cardDetails, NSDictionary)
19
16
  RCT_EXPORT_VIEW_PROPERTY(ephemeralKey, NSDictionary)
20
17
  RCT_EXPORT_VIEW_PROPERTY(onCompleteAction, RCTDirectEventBlock)
21
18
  @end
@@ -15,10 +15,7 @@ class AddToWalletButtonView: UIView {
15
15
 
16
16
  @objc var testEnv: Bool = false
17
17
  @objc var iOSButtonStyle: NSString?
18
- @objc var cardHolderName: NSString?
19
- @objc var cardDescription: NSString?
20
- @objc var cardLastFour: NSString?
21
- @objc var cardBrand: NSString?
18
+ @objc var cardDetails: NSDictionary?
22
19
  @objc var ephemeralKey: NSDictionary?
23
20
  @objc var onCompleteAction: RCTDirectEventBlock?
24
21
 
@@ -65,22 +62,22 @@ class AddToWalletButtonView: UIView {
65
62
  )
66
63
  return
67
64
  }
68
-
69
- guard let cardHolderName = cardHolderName as String? else {
65
+
66
+ guard let cardHolderName = cardDetails?["name"] as? String else {
70
67
  onCompleteAction!(
71
68
  Errors.createError(
72
69
  ErrorType.Failed,
73
- "Missing parameters. `cardHolderName` must be supplied in the props to <AddToWalletButton />"
70
+ "Missing parameters. `cardDetails.name` must be supplied in the props to <AddToWalletButton />"
74
71
  ) as? [AnyHashable : Any]
75
72
  )
76
73
  return
77
74
  }
78
-
75
+
79
76
  if (cardHolderName.isEmpty) {
80
77
  onCompleteAction!(
81
78
  Errors.createError(
82
79
  ErrorType.Failed,
83
- "`cardHolderName` is required, but the passed string was empty"
80
+ "`cardDetails.name` is required, but the passed string was empty"
84
81
  ) as? [AnyHashable : Any]
85
82
  )
86
83
  return
@@ -88,17 +85,18 @@ class AddToWalletButtonView: UIView {
88
85
 
89
86
  let config = STPPushProvisioningContext.requestConfiguration(
90
87
  withName: cardHolderName,
91
- description: cardDescription as String?,
92
- last4: cardLastFour as String?,
93
- brand: Mappers.mapToCardBrand(cardBrand as String?)
88
+ description: cardDetails?["description"] as? String,
89
+ last4: cardDetails?["lastFour"] as? String,
90
+ brand: Mappers.mapToCardBrand(cardDetails?["brand"] as? String),
91
+ primaryAccountIdentifier: cardDetails?["primaryAccountIdentifier"] as? String
94
92
  )
95
-
93
+
96
94
  // We can use STPFakeAddPaymentPassViewController ONLY IN TEST MODE. If STPFakeAddPaymentPassViewController is
97
95
  // used with a live mode card, the flow will fail and show a 'Signing certificate was invalid' error.
98
96
  let controller = {
99
97
  return self.testEnv ? STPFakeAddPaymentPassViewController(requestConfiguration: config, delegate: self) : PKAddPaymentPassViewController(requestConfiguration: config, delegate: self)
100
98
  }()
101
-
99
+
102
100
  let vc = findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController())
103
101
  vc.present(controller!, animated: true, completion: nil)
104
102
  }
@@ -1,2 +1,2 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _extends2=_interopRequireDefault(require("@babel/runtime/helpers/extends"));var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _reactNative=require("react-native");var _jsxFileName="/Users/acomley/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];var AddToWalletButtonNative=(0,_reactNative.requireNativeComponent)('AddToWalletButton');function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return _react.default.createElement(AddToWalletButtonNative,(0,_extends2.default)({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);},__self:this,__source:{fileName:_jsxFileName,lineNumber:77,columnNumber:5}}));}
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _extends2=_interopRequireDefault(require("@babel/runtime/helpers/extends"));var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _reactNative=require("react-native");var _jsxFileName="/Users/acomley/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];var AddToWalletButtonNative=(0,_reactNative.requireNativeComponent)('AddToWalletButton');function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return _react.default.createElement(AddToWalletButtonNative,(0,_extends2.default)({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);},__self:this,__source:{fileName:_jsxFileName,lineNumber:84,columnNumber:5}}));}
2
2
  //# sourceMappingURL=AddToWalletButton.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["AddToWalletButton.tsx"],"names":["AddToWalletButtonNative","AddToWalletButton","onComplete","props","value","nativeEvent"],"mappings":"wXAAA,oDACA,yC,+HAeA,GAAMA,CAAAA,uBAAuB,CAC3B,wCAA4B,mBAA5B,CADF,CA0DO,QAASC,CAAAA,iBAAT,MAA4D,IAA/BC,CAAAA,UAA+B,MAA/BA,UAA+B,CAAhBC,KAAgB,uDACjE,MACE,8BAAC,uBAAD,0BACMA,KADN,EAEE,gBAAgB,CAAE,0BAChBC,KADgB,QAIbF,CAAAA,UAAU,CAACE,KAAK,CAACC,WAAP,CAJG,EAFpB,6EADF,CAUD","sourcesContent":["import React from 'react';\nimport {\n AccessibilityProps,\n StyleProp,\n ViewStyle,\n requireNativeComponent,\n NativeSyntheticEvent,\n ImageSourcePropType,\n} from 'react-native';\nimport type {\n Token,\n CardActionError,\n StripeError,\n GooglePayCardToken,\n} from '../types';\n\nconst AddToWalletButtonNative =\n requireNativeComponent<any>('AddToWalletButton');\n\n/**\n * Add to wallet button component props\n */\nexport interface Props extends AccessibilityProps {\n style?: StyleProp<ViewStyle>;\n /** Sets the Apple Wallet/Google Pay button style. If the button is placed over a dark background, set this to 'onDarkBackground', otherwise set to 'onLightBackground'. */\n iOSButtonStyle?: 'onDarkBackground' | 'onLightBackground';\n /** The image asset to use as the Google Pay button. Downloadable from https://developers.google.com/pay/issuers/apis/push-provisioning/android/downloads/flutter/googlepay_flutter_buttons.zip */\n androidAssetSource: ImageSourcePropType;\n testID?: string;\n /** Only set to `false` when shipping through TestFlight || App Store */\n testEnv?: boolean;\n /** Sets the card holder name (used only on iOS) */\n cardHolderName: string;\n /** Last 4 digits of the card. Required on Android. */\n cardLastFour: string;\n /** Sets the card holder name (used only on iOS) */\n cardDescription?: string;\n /** Optional, only used on iOS */\n cardBrand?: Token.CardBrand;\n // Optional, only for Android and only for cards that are in the \"yellow path\" (as defined by Google- https://developers.google.com/pay/issuers/apis/push-provisioning/android/wallet-operations#resolving_yellow_path). Obtain this value via the `isCardInWallet` method.\n token?: GooglePayCardToken | null;\n /** Used by stripe to securely obtain card info of the card being provisioned. */\n ephemeralKey: object;\n /** Called when the flow completes. If the `error` field is `null`, then the card was successfully added to the user's native wallet. */\n onComplete(result: { error: StripeError<CardActionError> | null }): void;\n}\n\n/**\n * Add to wallet button\n *\n * @example\n * ```ts\n * <AddToWalletButton\n * testEnv={true}\n * style={styles.myButtonStyle}\n * iOSButtonStyle=\"onLightBackground\"\n * cardHolderName=\"David Wallace\"\n * cardLastFour=\"4242\"\n * cardBrand=\"Visa\"\n * ephemeralKey={myEphemeralKey} // This object is retrieved from your server. See https://stripe.com/docs/issuing/cards/digital-wallets?platform=react-native#update-your-backend\n * onComplete={(error) => {\n * Alert.alert(\n * error ? error.code : 'Success',\n * error\n * ? error.message\n * : 'Card was successfully added to the wallet.'\n * );\n * }}\n * />\n * ```\n * @param __namedParameters Props\n * @returns JSX.Element\n * @category ReactComponents\n */\nexport function AddToWalletButton({ onComplete, ...props }: Props) {\n return (\n <AddToWalletButtonNative\n {...props}\n onCompleteAction={(\n value: NativeSyntheticEvent<{\n error: StripeError<CardActionError> | null;\n }>\n ) => onComplete(value.nativeEvent)}\n />\n );\n}\n"]}
1
+ {"version":3,"sources":["AddToWalletButton.tsx"],"names":["AddToWalletButtonNative","AddToWalletButton","onComplete","props","value","nativeEvent"],"mappings":"wXAAA,oDACA,yC,+HAeA,GAAMA,CAAAA,uBAAuB,CAC3B,wCAA4B,mBAA5B,CADF,CAiEO,QAASC,CAAAA,iBAAT,MAA4D,IAA/BC,CAAAA,UAA+B,MAA/BA,UAA+B,CAAhBC,KAAgB,uDACjE,MACE,8BAAC,uBAAD,0BACMA,KADN,EAEE,gBAAgB,CAAE,0BAChBC,KADgB,QAIbF,CAAAA,UAAU,CAACE,KAAK,CAACC,WAAP,CAJG,EAFpB,6EADF,CAUD","sourcesContent":["import React from 'react';\nimport {\n AccessibilityProps,\n StyleProp,\n ViewStyle,\n requireNativeComponent,\n NativeSyntheticEvent,\n ImageSourcePropType,\n} from 'react-native';\nimport type {\n Token,\n CardActionError,\n StripeError,\n GooglePayCardToken,\n} from '../types';\n\nconst AddToWalletButtonNative =\n requireNativeComponent<any>('AddToWalletButton');\n\n/**\n * Add to wallet button component props\n */\nexport interface Props extends AccessibilityProps {\n style?: StyleProp<ViewStyle>;\n /** Sets the Apple Wallet/Google Pay button style. If the button is placed over a dark background, set this to 'onDarkBackground', otherwise set to 'onLightBackground'. */\n iOSButtonStyle?: 'onDarkBackground' | 'onLightBackground';\n /** The image asset to use as the Google Pay button. Downloadable from https://developers.google.com/pay/issuers/apis/push-provisioning/android/downloads/flutter/googlepay_flutter_buttons.zip */\n androidAssetSource: ImageSourcePropType;\n testID?: string;\n /** Only set to `false` when shipping through TestFlight || App Store */\n testEnv?: boolean;\n /** Details of the Issued Card you'd like added to the device's wallet */\n cardDetails: {\n /** The `primary_account_identifier` value from the issued card. */\n primaryAccountIdentifier: string | null;\n /** The card holder name (used only on iOS) */\n name: string;\n /** A user-facing description of the card. Required on Android.*/\n description: string;\n /** Last 4 digits of the card, only used on iOS */\n lastFour?: string;\n /** Optional, only used on iOS */\n brand?: Token.CardBrand;\n };\n // Optional, only for Android and only for cards that are in the \"yellow path\" (as defined by Google- https://developers.google.com/pay/issuers/apis/push-provisioning/android/wallet-operations#resolving_yellow_path). Obtain this value via the `isCardInWallet` method.\n token?: GooglePayCardToken | null;\n /** Used by stripe to securely obtain card info of the card being provisioned. */\n ephemeralKey: object;\n /** Called when the flow completes. If the `error` field is `null`, then the card was successfully added to the user's native wallet. */\n onComplete(result: { error: StripeError<CardActionError> | null }): void;\n}\n\n/**\n * Add to wallet button\n *\n * @example\n * ```ts\n * <AddToWalletButton\n * testEnv={true}\n * style={styles.myButtonStyle}\n * iOSButtonStyle=\"onLightBackground\"\n * cardDetails={{\n * primaryAccountIdentifier: \"V-123\",\n * name: \"David Wallace\",\n * lastFour: \"4242\",\n * }}\n * ephemeralKey={myEphemeralKey} // This object is retrieved from your server. See https://stripe.com/docs/issuing/cards/digital-wallets?platform=react-native#update-your-backend\n * onComplete={(error) => {\n * Alert.alert(\n * error ? error.code : 'Success',\n * error\n * ? error.message\n * : 'Card was successfully added to the wallet.'\n * );\n * }}\n * />\n * ```\n * @param __namedParameters Props\n * @returns JSX.Element\n * @category ReactComponents\n */\nexport function AddToWalletButton({ onComplete, ...props }: Props) {\n return (\n <AddToWalletButtonNative\n {...props}\n onCompleteAction={(\n value: NativeSyntheticEvent<{\n error: StripeError<CardActionError> | null;\n }>\n ) => onComplete(value.nativeEvent)}\n />\n );\n}\n"]}