@stripe/stripe-react-native 0.28.0 → 0.30.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 (123) hide show
  1. package/CHANGELOG.md +95 -68
  2. package/README.md +2 -2
  3. package/android/gradle.properties +1 -1
  4. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonManager.kt +0 -5
  5. package/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt +11 -27
  6. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +35 -8
  7. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +131 -6
  8. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +42 -7
  9. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/TapAndPayProxy.kt +8 -1
  10. package/android/src/main/java/com/reactnativestripesdk/utils/Errors.kt +2 -0
  11. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +14 -1
  12. package/ios/ApplePayButtonView.swift +4 -18
  13. package/ios/ApplePayViewController.swift +1 -28
  14. package/ios/Mappers.swift +1 -0
  15. package/ios/StripeSdk+PaymentSheet.swift +100 -10
  16. package/ios/StripeSdk.m +22 -29
  17. package/ios/StripeSdk.swift +59 -85
  18. package/jest/mock.js +4 -6
  19. package/lib/commonjs/NativeStripeSdk.js.map +1 -1
  20. package/lib/commonjs/components/ApplePayButtonNative.js.map +1 -1
  21. package/lib/commonjs/components/GooglePayButtonNative.js.map +1 -1
  22. package/lib/commonjs/functions.js +1 -1
  23. package/lib/commonjs/functions.js.map +1 -1
  24. package/lib/commonjs/hooks/useFinancialConnectionsSheet.js +1 -1
  25. package/lib/commonjs/hooks/useFinancialConnectionsSheet.js.map +1 -1
  26. package/lib/commonjs/hooks/usePaymentSheet.js +1 -1
  27. package/lib/commonjs/hooks/usePaymentSheet.js.map +1 -1
  28. package/lib/commonjs/hooks/useStripe.js +1 -1
  29. package/lib/commonjs/hooks/useStripe.js.map +1 -1
  30. package/lib/commonjs/index.js +1 -1
  31. package/lib/commonjs/index.js.map +1 -1
  32. package/lib/commonjs/types/ApplePay.js.map +1 -1
  33. package/lib/commonjs/types/PaymentIntent.js.map +1 -1
  34. package/lib/commonjs/types/PaymentSheet.js +1 -1
  35. package/lib/commonjs/types/PaymentSheet.js.map +1 -1
  36. package/lib/commonjs/types/PlatformPay.js.map +1 -1
  37. package/lib/commonjs/types/PushProvisioning.js.map +1 -1
  38. package/lib/commonjs/types/components/GooglePayButtonComponent.js.map +1 -1
  39. package/lib/commonjs/types/index.js +1 -1
  40. package/lib/commonjs/types/index.js.map +1 -1
  41. package/lib/module/NativeStripeSdk.js.map +1 -1
  42. package/lib/module/components/ApplePayButtonNative.js.map +1 -1
  43. package/lib/module/components/GooglePayButtonNative.js.map +1 -1
  44. package/lib/module/functions.js +1 -1
  45. package/lib/module/functions.js.map +1 -1
  46. package/lib/module/hooks/useFinancialConnectionsSheet.js +1 -1
  47. package/lib/module/hooks/useFinancialConnectionsSheet.js.map +1 -1
  48. package/lib/module/hooks/usePaymentSheet.js +1 -1
  49. package/lib/module/hooks/usePaymentSheet.js.map +1 -1
  50. package/lib/module/hooks/useStripe.js +1 -1
  51. package/lib/module/hooks/useStripe.js.map +1 -1
  52. package/lib/module/index.js +1 -1
  53. package/lib/module/index.js.map +1 -1
  54. package/lib/module/types/ApplePay.js.map +1 -1
  55. package/lib/module/types/PaymentIntent.js.map +1 -1
  56. package/lib/module/types/PaymentSheet.js +1 -1
  57. package/lib/module/types/PaymentSheet.js.map +1 -1
  58. package/lib/module/types/PlatformPay.js.map +1 -1
  59. package/lib/module/types/PushProvisioning.js.map +1 -1
  60. package/lib/module/types/components/GooglePayButtonComponent.js.map +1 -1
  61. package/lib/module/types/index.js +1 -1
  62. package/lib/module/types/index.js.map +1 -1
  63. package/lib/typescript/src/NativeStripeSdk.d.ts +5 -15
  64. package/lib/typescript/src/components/ApplePayButtonNative.d.ts +1 -1
  65. package/lib/typescript/src/components/GooglePayButtonNative.d.ts +1 -1
  66. package/lib/typescript/src/functions.d.ts +15 -27
  67. package/lib/typescript/src/hooks/usePlatformPay.d.ts +1 -1
  68. package/lib/typescript/src/hooks/useStripe.d.ts +3 -18
  69. package/lib/typescript/src/index.d.ts +0 -7
  70. package/lib/typescript/src/types/ApplePay.d.ts +0 -52
  71. package/lib/typescript/src/types/PaymentIntent.d.ts +3 -2
  72. package/lib/typescript/src/types/PaymentSheet.d.ts +48 -2
  73. package/lib/typescript/src/types/PlatformPay.d.ts +34 -4
  74. package/lib/typescript/src/types/PushProvisioning.d.ts +9 -1
  75. package/lib/typescript/src/types/components/GooglePayButtonComponent.d.ts +0 -1
  76. package/lib/typescript/src/types/index.d.ts +8 -4
  77. package/package.json +1 -1
  78. package/src/NativeStripeSdk.tsx +11 -31
  79. package/src/components/ApplePayButtonNative.tsx +1 -1
  80. package/src/components/GooglePayButtonNative.tsx +1 -1
  81. package/src/functions.ts +87 -197
  82. package/src/hooks/useFinancialConnectionsSheet.tsx +19 -13
  83. package/src/hooks/usePaymentSheet.tsx +25 -18
  84. package/src/hooks/useStripe.tsx +14 -108
  85. package/src/index.tsx +0 -7
  86. package/src/types/ApplePay.ts +0 -71
  87. package/src/types/PaymentIntent.ts +4 -2
  88. package/src/types/PaymentSheet.ts +86 -2
  89. package/src/types/PlatformPay.ts +35 -4
  90. package/src/types/PushProvisioning.ts +9 -1
  91. package/src/types/components/GooglePayButtonComponent.ts +0 -1
  92. package/src/types/index.ts +10 -6
  93. package/stripe-react-native.podspec +1 -1
  94. package/lib/commonjs/components/ApplePayButton.js +0 -2
  95. package/lib/commonjs/components/ApplePayButton.js.map +0 -1
  96. package/lib/commonjs/components/GooglePayButton.js +0 -2
  97. package/lib/commonjs/components/GooglePayButton.js.map +0 -1
  98. package/lib/commonjs/hooks/useApplePay.js +0 -2
  99. package/lib/commonjs/hooks/useApplePay.js.map +0 -1
  100. package/lib/commonjs/hooks/useGooglePay.js +0 -2
  101. package/lib/commonjs/hooks/useGooglePay.js.map +0 -1
  102. package/lib/commonjs/types/GooglePay.js +0 -2
  103. package/lib/commonjs/types/GooglePay.js.map +0 -1
  104. package/lib/module/components/ApplePayButton.js +0 -2
  105. package/lib/module/components/ApplePayButton.js.map +0 -1
  106. package/lib/module/components/GooglePayButton.js +0 -2
  107. package/lib/module/components/GooglePayButton.js.map +0 -1
  108. package/lib/module/hooks/useApplePay.js +0 -2
  109. package/lib/module/hooks/useApplePay.js.map +0 -1
  110. package/lib/module/hooks/useGooglePay.js +0 -2
  111. package/lib/module/hooks/useGooglePay.js.map +0 -1
  112. package/lib/module/types/GooglePay.js +0 -2
  113. package/lib/module/types/GooglePay.js.map +0 -1
  114. package/lib/typescript/src/components/ApplePayButton.d.ts +0 -31
  115. package/lib/typescript/src/components/GooglePayButton.d.ts +0 -26
  116. package/lib/typescript/src/hooks/useApplePay.d.ts +0 -54
  117. package/lib/typescript/src/hooks/useGooglePay.d.ts +0 -11
  118. package/lib/typescript/src/types/GooglePay.d.ts +0 -47
  119. package/src/components/ApplePayButton.tsx +0 -108
  120. package/src/components/GooglePayButton.tsx +0 -58
  121. package/src/hooks/useApplePay.tsx +0 -161
  122. package/src/hooks/useGooglePay.tsx +0 -72
  123. package/src/types/GooglePay.ts +0 -74
@@ -17,16 +17,15 @@ import android.widget.FrameLayout
17
17
  import androidx.appcompat.content.res.AppCompatResources
18
18
  import androidx.core.graphics.drawable.DrawableCompat
19
19
  import androidx.fragment.app.Fragment
20
- import com.facebook.react.bridge.Promise
21
- import com.facebook.react.bridge.ReactApplicationContext
22
- import com.facebook.react.bridge.WritableMap
23
- import com.facebook.react.bridge.WritableNativeMap
20
+ import com.facebook.react.bridge.*
24
21
  import com.reactnativestripesdk.addresssheet.AddressSheetView
25
22
  import com.reactnativestripesdk.utils.*
26
23
  import com.reactnativestripesdk.utils.createError
27
24
  import com.reactnativestripesdk.utils.createResult
28
25
  import com.stripe.android.paymentsheet.*
26
+ import kotlinx.coroutines.CompletableDeferred
29
27
  import java.io.ByteArrayOutputStream
28
+ import kotlin.Exception
30
29
 
31
30
  class PaymentSheetFragment(
32
31
  private val context: ReactApplicationContext,
@@ -36,10 +35,12 @@ class PaymentSheetFragment(
36
35
  private var flowController: PaymentSheet.FlowController? = null
37
36
  private var paymentIntentClientSecret: String? = null
38
37
  private var setupIntentClientSecret: String? = null
38
+ private var intentConfiguration: PaymentSheet.IntentConfiguration? = null
39
39
  private lateinit var paymentSheetConfiguration: PaymentSheet.Configuration
40
40
  private var confirmPromise: Promise? = null
41
41
  private var presentPromise: Promise? = null
42
42
  private var paymentSheetTimedOut = false
43
+ internal val paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
43
44
 
44
45
  override fun onCreateView(
45
46
  inflater: LayoutInflater,
@@ -67,6 +68,12 @@ class PaymentSheetFragment(
67
68
  val billingConfigParams = arguments?.getBundle("billingDetailsCollectionConfiguration")
68
69
  paymentIntentClientSecret = arguments?.getString("paymentIntentClientSecret").orEmpty()
69
70
  setupIntentClientSecret = arguments?.getString("setupIntentClientSecret").orEmpty()
71
+ intentConfiguration = try {
72
+ buildIntentConfiguration(arguments?.getBundle("intentConfiguration"))
73
+ } catch (error: PaymentSheetException) {
74
+ initPromise.resolve(createError(ErrorType.Failed.toString(), error))
75
+ return
76
+ }
70
77
  val appearance = try {
71
78
  buildPaymentSheetAppearance(arguments?.getBundle("appearance"), context)
72
79
  } catch (error: PaymentSheetAppearanceException) {
@@ -120,6 +127,34 @@ class PaymentSheetFragment(
120
127
  }
121
128
  }
122
129
 
130
+ val createIntentCallback = CreateIntentCallback { paymentMethod, shouldSavePaymentMethod ->
131
+ val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
132
+ if (stripeSdkModule == null || stripeSdkModule.eventListenerCount == 0) {
133
+ return@CreateIntentCallback CreateIntentResult.Failure(
134
+ cause = Exception("Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues"),
135
+ displayMessage = "An unexpected error occurred"
136
+ )
137
+ }
138
+ val params = Arguments.createMap().apply {
139
+ putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
140
+ putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
141
+ }
142
+
143
+ stripeSdkModule.sendEvent(context, "onConfirmHandlerCallback", params)
144
+
145
+ val resultFromJavascript = paymentSheetIntentCreationCallback.await()
146
+
147
+ return@CreateIntentCallback resultFromJavascript.getString("clientSecret")?.let {
148
+ CreateIntentResult.Success(clientSecret = it)
149
+ } ?: run {
150
+ val errorMap = resultFromJavascript.getMap("error")
151
+ CreateIntentResult.Failure(
152
+ cause = Exception(errorMap?.getString("message")),
153
+ displayMessage = errorMap?.getString("localizedMessage")
154
+ )
155
+ }
156
+ }
157
+
123
158
  val billingDetailsConfig = PaymentSheet.BillingDetailsCollectionConfiguration(
124
159
  name = mapToCollectionMode(billingConfigParams?.getString("name")),
125
160
  phone = mapToCollectionMode(billingConfigParams?.getString("phone")),
@@ -162,10 +197,34 @@ class PaymentSheetFragment(
162
197
  )
163
198
 
164
199
  if (arguments?.getBoolean("customFlow") == true) {
165
- flowController = PaymentSheet.FlowController.create(this, paymentOptionCallback, paymentResultCallback)
200
+ flowController = if (intentConfiguration != null) {
201
+ PaymentSheet.FlowController.create(
202
+ this,
203
+ paymentOptionCallback = paymentOptionCallback,
204
+ createIntentCallback = createIntentCallback,
205
+ paymentResultCallback = paymentResultCallback
206
+ )
207
+ } else {
208
+ PaymentSheet.FlowController.create(
209
+ this,
210
+ paymentOptionCallback = paymentOptionCallback,
211
+ paymentResultCallback = paymentResultCallback
212
+ )
213
+ }
166
214
  configureFlowController()
167
215
  } else {
168
- paymentSheet = PaymentSheet(this, paymentResultCallback)
216
+ paymentSheet = if (intentConfiguration != null) {
217
+ PaymentSheet(
218
+ this,
219
+ createIntentCallback = createIntentCallback,
220
+ paymentResultCallback = paymentResultCallback
221
+ )
222
+ } else {
223
+ PaymentSheet(
224
+ this,
225
+ callback = paymentResultCallback
226
+ )
227
+ }
169
228
  initPromise.resolve(WritableNativeMap())
170
229
  }
171
230
  }
@@ -177,6 +236,11 @@ class PaymentSheetFragment(
177
236
  paymentSheet?.presentWithPaymentIntent(paymentIntentClientSecret!!, paymentSheetConfiguration)
178
237
  } else if (!setupIntentClientSecret.isNullOrEmpty()) {
179
238
  paymentSheet?.presentWithSetupIntent(setupIntentClientSecret!!, paymentSheetConfiguration)
239
+ } else if (intentConfiguration != null) {
240
+ paymentSheet?.presentWithIntentConfiguration(
241
+ intentConfiguration = intentConfiguration!!,
242
+ configuration = paymentSheetConfiguration
243
+ )
180
244
  }
181
245
  } else if(flowController != null) {
182
246
  flowController?.presentPaymentOptions()
@@ -253,6 +317,15 @@ class PaymentSheetFragment(
253
317
  configuration = paymentSheetConfiguration,
254
318
  callback = onFlowControllerConfigure
255
319
  )
320
+ } else if (intentConfiguration != null) {
321
+ flowController?.configureWithIntentConfiguration(
322
+ intentConfiguration = intentConfiguration!!,
323
+ configuration = paymentSheetConfiguration,
324
+ callback = onFlowControllerConfigure
325
+ )
326
+ } else {
327
+ initPromise.resolve(createError(ErrorType.Failed.toString(), "One of `paymentIntentClientSecret`, `setupIntentClientSecret`, or `intentConfiguration` is required"))
328
+ return
256
329
  }
257
330
  }
258
331
 
@@ -287,6 +360,41 @@ class PaymentSheetFragment(
287
360
  currencyCode = currencyCode
288
361
  )
289
362
  }
363
+
364
+ @Throws(PaymentSheetException::class)
365
+ private fun buildIntentConfiguration(intentConfigurationParams: Bundle?): PaymentSheet.IntentConfiguration? {
366
+ if (intentConfigurationParams == null) {
367
+ return null
368
+ }
369
+ val modeParams = intentConfigurationParams.getBundle("mode")
370
+ ?: throw PaymentSheetException("If `intentConfiguration` is provided, `intentConfiguration.mode` is required")
371
+
372
+ return PaymentSheet.IntentConfiguration(
373
+ mode = buildIntentConfigurationMode(modeParams),
374
+ paymentMethodTypes = intentConfigurationParams.getStringArrayList("paymentMethodTypes")?.toList() ?: emptyList(),
375
+ )
376
+ }
377
+
378
+ private fun buildIntentConfigurationMode(modeParams: Bundle): PaymentSheet.IntentConfiguration.Mode {
379
+ val currencyCode = modeParams.getString("currencyCode")
380
+ ?: throw PaymentSheetException("You must provide a value to intentConfiguration.mode.currencyCode")
381
+
382
+ return if (modeParams.containsKey("amount")) {
383
+ PaymentSheet.IntentConfiguration.Mode.Payment(
384
+ amount = modeParams.getInt("amount").toLong(),
385
+ currency = currencyCode,
386
+ setupFutureUse = mapToSetupFutureUse(modeParams.getString("setupFutureUsage")),
387
+ captureMethod = mapToCaptureMethod(modeParams.getString("captureMethod")),
388
+ )
389
+ } else {
390
+ val setupFutureUsage = mapToSetupFutureUse(modeParams.getString("setupFutureUsage"))
391
+ ?: throw PaymentSheetException("You must provide a value to intentConfiguration.mode.setupFutureUsage")
392
+ PaymentSheet.IntentConfiguration.Mode.Setup(
393
+ currency = currencyCode,
394
+ setupFutureUse = setupFutureUsage
395
+ )
396
+ }
397
+ }
290
398
  }
291
399
  }
292
400
 
@@ -329,3 +437,20 @@ fun mapToAddressCollectionMode(str: String?): PaymentSheet.BillingDetailsCollect
329
437
  else -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Automatic
330
438
  }
331
439
  }
440
+
441
+ fun mapToSetupFutureUse(type: String?): PaymentSheet.IntentConfiguration.SetupFutureUse? {
442
+ return when (type) {
443
+ "OffSession" -> PaymentSheet.IntentConfiguration.SetupFutureUse.OffSession
444
+ "OnSession" -> PaymentSheet.IntentConfiguration.SetupFutureUse.OnSession
445
+ else -> null
446
+ }
447
+ }
448
+
449
+ fun mapToCaptureMethod(type: String?): PaymentSheet.IntentConfiguration.CaptureMethod {
450
+ return when (type) {
451
+ "Automatic" -> PaymentSheet.IntentConfiguration.CaptureMethod.Automatic
452
+ "Manual" -> PaymentSheet.IntentConfiguration.CaptureMethod.Manual
453
+ "AutomaticAsync" -> PaymentSheet.IntentConfiguration.CaptureMethod.AutomaticAsync
454
+ else -> PaymentSheet.IntentConfiguration.CaptureMethod.Automatic
455
+ }
456
+ }
@@ -7,6 +7,7 @@ import android.util.Log
7
7
  import androidx.fragment.app.FragmentActivity
8
8
  import com.facebook.react.bridge.*
9
9
  import com.facebook.react.module.annotations.ReactModule
10
+ import com.facebook.react.modules.core.DeviceEventManagerModule
10
11
  import com.reactnativestripesdk.addresssheet.AddressLauncherFragment
11
12
  import com.reactnativestripesdk.pushprovisioning.PushProvisioningProxy
12
13
  import com.reactnativestripesdk.utils.*
@@ -47,6 +48,8 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
47
48
  private var paymentLauncherFragment: PaymentLauncherFragment? = null
48
49
  private var collectBankAccountLauncherFragment: CollectBankAccountLauncherFragment? = null
49
50
 
51
+ internal var eventListenerCount = 0
52
+
50
53
  // If you create a new Fragment, you must put the tag here, otherwise result callbacks for that
51
54
  // Fragment will not work on RN < 0.65
52
55
  private val allStripeFragmentTags: List<String>
@@ -204,6 +207,16 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
204
207
  promise.resolve(null)
205
208
  }
206
209
 
210
+ @ReactMethod
211
+ fun intentCreationCallback(params: ReadableMap, promise: Promise) {
212
+ if (paymentSheetFragment == null) {
213
+ promise.resolve(PaymentSheetFragment.createMissingInitError())
214
+ return
215
+ }
216
+
217
+ paymentSheetFragment?.paymentSheetIntentCreationCallback?.complete(params)
218
+ }
219
+
207
220
  private fun payWithFpx() {
208
221
  getCurrentActivityOrResolveWithError(confirmPromise)?.let {
209
222
  AddPaymentMethodActivityStarter(it)
@@ -393,7 +406,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
393
406
 
394
407
  @ReactMethod
395
408
  fun handleNextAction(paymentIntentClientSecret: String, promise: Promise) {
396
- paymentLauncherFragment = PaymentLauncherFragment.forNextAction(
409
+ paymentLauncherFragment = PaymentLauncherFragment.forNextActionPayment(
397
410
  context = reactApplicationContext,
398
411
  stripe,
399
412
  publishableKey,
@@ -403,6 +416,18 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
403
416
  )
404
417
  }
405
418
 
419
+ @ReactMethod
420
+ fun handleNextActionForSetup(setupIntentClientSecret: String, promise: Promise) {
421
+ paymentLauncherFragment = PaymentLauncherFragment.forNextActionSetup(
422
+ context = reactApplicationContext,
423
+ stripe,
424
+ publishableKey,
425
+ stripeAccountId,
426
+ promise,
427
+ setupIntentClientSecret
428
+ )
429
+ }
430
+
406
431
  // TODO: Uncomment when WeChat is re-enabled in stripe-ios
407
432
  // private fun payWithWeChatPay(paymentIntentClientSecret: String, appId: String) {
408
433
  // val activity = currentActivity as ComponentActivity
@@ -866,14 +891,24 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
866
891
  }
867
892
  }
868
893
 
869
- /**
870
- * We need the following in order to avoid some annoying console.warns() from our Apple Pay event listeners. Otherwise,
871
- * we'd have to put our users through some annoying (if Platform.OS...) logic & null-handling logic.
872
- */
873
894
  @ReactMethod
874
- fun addListener(eventName: String) {}
895
+ fun addListener(eventName: String) {
896
+ eventListenerCount++
897
+ }
898
+
875
899
  @ReactMethod
876
- fun removeListeners(count: Int) {}
900
+ fun removeListeners(count: Int) {
901
+ eventListenerCount -= count
902
+ if (eventListenerCount < 0) {
903
+ eventListenerCount = 0
904
+ }
905
+ }
906
+
907
+ internal fun sendEvent(reactContext: ReactContext, eventName: String, params: WritableMap) {
908
+ reactContext
909
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
910
+ .emit(eventName, params)
911
+ }
877
912
 
878
913
  /**
879
914
  * Safely get and cast the current activity as an AppCompatActivity. If that fails, the promise
@@ -91,9 +91,16 @@ object TapAndPayProxy {
91
91
  result.putString(
92
92
  "id",
93
93
  tokenInfoClass.getMethod("getIssuerTokenId").invoke(it) as String)
94
+ val fpan = tokenInfoClass.getMethod("getFpanLastFour").invoke(it) as String
94
95
  result.putString(
95
96
  "cardLastFour",
96
- tokenInfoClass.getMethod("getFpanLastFour").invoke(it) as String)
97
+ fpan)
98
+ result.putString(
99
+ "fpanLastFour",
100
+ fpan)
101
+ result.putString(
102
+ "dpanLastFour",
103
+ tokenInfoClass.getMethod("getDpanLastFour").invoke(it) as String)
97
104
  result.putString(
98
105
  "issuer",
99
106
  tokenInfoClass.getMethod("getIssuerName").invoke(it) as String)
@@ -43,6 +43,8 @@ enum class GooglePayErrorType {
43
43
 
44
44
  class PaymentSheetAppearanceException(message: String) : Exception(message)
45
45
 
46
+ class PaymentSheetException(message: String) : Exception(message)
47
+
46
48
  internal fun mapError(code: String, message: String?, localizedMessage: String?, declineCode: String?, type: String?, stripeErrorCode: String?): WritableMap {
47
49
  val map: WritableMap = WritableNativeMap()
48
50
  val details: WritableMap = WritableNativeMap()
@@ -856,7 +856,20 @@ fun toBundleObject(readableMap: ReadableMap?): Bundle {
856
856
  }
857
857
  ReadableType.String -> result.putString(key, readableMap.getString(key))
858
858
  ReadableType.Map -> result.putBundle(key, toBundleObject(readableMap.getMap(key)))
859
- ReadableType.Array -> Log.e("toBundleException", "Cannot put arrays of objects into bundles. Failed on: $key.")
859
+ ReadableType.Array -> {
860
+ val list = readableMap.getArray(key)?.toArrayList()
861
+ if (list == null) {
862
+ result.putString(key, null)
863
+ } else if (list.isEmpty()) {
864
+ result.putStringArrayList(key, ArrayList())
865
+ } else {
866
+ when (list.first()) {
867
+ is String -> result.putStringArrayList(key, list as java.util.ArrayList<String>)
868
+ is Int -> result.putIntegerArrayList(key, list as java.util.ArrayList<Int>)
869
+ else -> Log.e("toBundleException", "Cannot put arrays of objects into bundles. Failed on: $key.")
870
+ }
871
+ }
872
+ }
860
873
  else -> Log.e("toBundleException", "Could not convert object with key: $key.")
861
874
  }
862
875
  }
@@ -17,25 +17,11 @@ class ApplePayButtonView: UIView {
17
17
  @objc var borderRadius: NSNumber?
18
18
  @objc var disabled = false
19
19
 
20
- func doesNothing(_: Optional<Dictionary<AnyHashable, Any>>) {
21
- return
22
- }
23
-
24
20
  @objc func handleApplePayButtonTapped() {
25
- if onPressAction != nil {
26
- onPressAction!(["true": true])
27
- // JS Callbacks are all no-ops since in legacy code (useApplePay hook),
28
- // this behavior is controlled via the onDidSetShippingMethod and onDidSetShippingContact
29
- // events
30
- stripeSdk?.shippingMethodUpdateJSCallback = doesNothing
31
- stripeSdk?.shippingContactUpdateJSCallback = doesNothing
32
- stripeSdk?.couponCodeEnteredJSCallback = doesNothing
33
- } else {
34
- stripeSdk?.shippingMethodUpdateJSCallback = onShippingMethodSelectedAction
35
- stripeSdk?.shippingContactUpdateJSCallback = onShippingContactSelectedAction
36
- stripeSdk?.couponCodeEnteredJSCallback = onCouponCodeEnteredAction
37
- stripeSdk?.platformPayOrderTrackingJSCallback = onOrderTrackingAction
38
- }
21
+ stripeSdk?.shippingMethodUpdateJSCallback = onShippingMethodSelectedAction
22
+ stripeSdk?.shippingContactUpdateJSCallback = onShippingContactSelectedAction
23
+ stripeSdk?.couponCodeEnteredJSCallback = onCouponCodeEnteredAction
24
+ stripeSdk?.platformPayOrderTrackingJSCallback = onOrderTrackingAction
39
25
  }
40
26
 
41
27
  override func didSetProps(_ changedProps: [String]!) {
@@ -122,10 +122,6 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC
122
122
  didSelect shippingMethod: PKShippingMethod,
123
123
  handler: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void
124
124
  ) {
125
- if (self.hasLegacyApplePayListeners) {
126
- // Legacy, remove when useApplePay hook is removed
127
- sendEvent(withName: "onDidSetShippingMethod", body: ["shippingMethod": Mappers.mapFromShippingMethod(shippingMethod: shippingMethod)])
128
- }
129
125
  if let callback = self.shippingMethodUpdateJSCallback {
130
126
  self.shippingMethodUpdateCompletion = handler
131
127
  callback(["shippingMethod": Mappers.mapFromShippingMethod(shippingMethod: shippingMethod)])
@@ -141,10 +137,6 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC
141
137
  didSelectShippingContact contact: PKContact,
142
138
  handler: @escaping (PKPaymentRequestShippingContactUpdate) -> Void
143
139
  ) {
144
- if (self.hasLegacyApplePayListeners) {
145
- // Legacy, remove when useApplePay hook is removed
146
- sendEvent(withName: "onDidSetShippingContact", body: ["shippingContact": Mappers.mapFromShippingContact(shippingContact: contact)])
147
- }
148
140
  if let callback = self.shippingContactUpdateJSCallback {
149
141
  self.shippingContactUpdateCompletion = handler
150
142
  callback(["shippingContact": Mappers.mapFromShippingContact(shippingContact: contact)])
@@ -170,10 +162,7 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC
170
162
  } else if let clientSecret = self.confirmApplePaySetupClientSecret {
171
163
  completion(clientSecret, nil)
172
164
  } else {
173
- self.applePayCompletionCallback = completion
174
- let method = Mappers.mapFromPaymentMethod(paymentMethod.splitApplePayAddressByNewline())
175
- self.deprecatedApplePayRequestResolver?(Mappers.createResult("paymentMethod", method))
176
- self.deprecatedApplePayRequestRejecter = nil
165
+ RCTMakeAndLogError("Tried to complete Apple Pay payment, but no client secret was found.", nil, nil)
177
166
  }
178
167
  }
179
168
 
@@ -233,44 +222,28 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC
233
222
  }
234
223
  }
235
224
  }
236
-
237
- } else {
238
- deprecatedConfirmApplePayPaymentResolver?([])
239
225
  }
240
226
  break
241
227
  case .error:
242
228
  if let resolve = self.confirmApplePayResolver {
243
229
  resolve(Errors.createError(ErrorType.Failed, error as NSError?))
244
- } else {
245
- let message = "Payment not completed"
246
- deprecatedApplePayCompletionRejecter?(ErrorType.Failed, message, nil)
247
- deprecatedApplePayRequestRejecter?(ErrorType.Failed, message, nil)
248
230
  }
249
231
  break
250
232
  case .userCancellation:
251
233
  let message = "The payment has been canceled"
252
234
  if let resolve = self.confirmApplePayResolver {
253
235
  resolve(Errors.createError(ErrorType.Canceled, message))
254
- } else {
255
- deprecatedApplePayCompletionRejecter?(ErrorType.Canceled, message, nil)
256
- deprecatedApplePayRequestRejecter?(ErrorType.Canceled, message, nil)
257
236
  }
258
237
  break
259
238
  @unknown default:
260
239
  if let resolve = self.confirmApplePayResolver {
261
240
  resolve(Errors.createError(ErrorType.Unknown, error as NSError?))
262
- } else {
263
- let message = "Payment not completed"
264
- deprecatedApplePayCompletionRejecter?(ErrorType.Unknown, message, nil)
265
- deprecatedApplePayRequestRejecter?(ErrorType.Unknown, message, nil)
266
241
  }
267
242
  break
268
243
  }
269
244
  confirmApplePayResolver = nil
270
245
  confirmApplePayPaymentClientSecret = nil
271
246
  confirmApplePaySetupClientSecret = nil
272
- deprecatedApplePayCompletionRejecter = nil
273
- deprecatedApplePayRequestRejecter = nil
274
247
  }
275
248
 
276
249
  }
package/ios/Mappers.swift CHANGED
@@ -357,6 +357,7 @@ class Mappers {
357
357
  if let address = shipping.address {
358
358
  addressDetails = [
359
359
  "city": address.city ?? NSNull(),
360
+ "state": address.state ?? NSNull(),
360
361
  "country": address.country ?? NSNull(),
361
362
  "line1": address.line1 ?? NSNull(),
362
363
  "line2":address.line2 ?? NSNull(),
@@ -9,7 +9,9 @@ import Foundation
9
9
  import StripePaymentSheet
10
10
 
11
11
  extension StripeSdk {
12
- internal func buildPaymentSheetConfiguration(params: NSDictionary, orderTrackingCallback: RCTResponseSenderBlock? = nil) -> (error: NSDictionary?, configuration: PaymentSheet.Configuration?) {
12
+ internal func buildPaymentSheetConfiguration(
13
+ params: NSDictionary
14
+ ) -> (error: NSDictionary?, configuration: PaymentSheet.Configuration?) {
13
15
  var configuration = PaymentSheet.Configuration()
14
16
 
15
17
  configuration.primaryButtonLabel = params["primaryButtonLabel"] as? String
@@ -29,7 +31,7 @@ extension StripeSdk {
29
31
  merchantCountryCode: applePayParams["merchantCountryCode"] as? String,
30
32
  paymentSummaryItems: applePayParams["cartItems"] as? [[String : Any]],
31
33
  buttonType: applePayParams["buttonType"] as? NSNumber,
32
- customHandlers: buildCustomerHandlersForPaymentSheet(applePayParams: applePayParams, orderTrackingCallback: orderTrackingCallback)
34
+ customHandlers: buildCustomerHandlersForPaymentSheet(applePayParams: applePayParams)
33
35
  )
34
36
  } catch {
35
37
  return(error: Errors.createError(ErrorType.Failed, error.localizedDescription), configuration: nil)
@@ -96,8 +98,13 @@ extension StripeSdk {
96
98
  return (nil, configuration)
97
99
  }
98
100
 
99
- internal func preparePaymentSheetInstance(params: NSDictionary, configuration: PaymentSheet.Configuration, resolve: @escaping RCTPromiseResolveBlock) {
100
-
101
+ internal func preparePaymentSheetInstance(
102
+ params: NSDictionary,
103
+ configuration: PaymentSheet.Configuration,
104
+ resolve: @escaping RCTPromiseResolveBlock
105
+ ) {
106
+ self.paymentSheetFlowController = nil
107
+
101
108
  func handlePaymentSheetFlowControllerResult(result: Result<PaymentSheet.FlowController, Error>, stripeSdk: StripeSdk?) {
102
109
  switch result {
103
110
  case .failure(let error):
@@ -146,12 +153,91 @@ extension StripeSdk {
146
153
  resolve([])
147
154
  }
148
155
  } else {
149
- resolve(Errors.createError(ErrorType.Failed, "You must provide either paymentIntentClientSecret or setupIntentClientSecret"))
156
+ guard let intentConfiguration = params["intentConfiguration"] as? NSDictionary else {
157
+ resolve(Errors.createError(ErrorType.Failed, "One of `paymentIntentClientSecret`, `setupIntentClientSecret`, or `intentConfiguration` is required"))
158
+ return
159
+ }
160
+ guard let modeParams = intentConfiguration["mode"] as? NSDictionary else {
161
+ resolve(Errors.createError(ErrorType.Failed, "One of `paymentIntentClientSecret`, `setupIntentClientSecret`, or `intentConfiguration.mode` is required"))
162
+ return
163
+ }
164
+ if (intentConfiguration.object(forKey: "confirmHandler") == nil) {
165
+ resolve(Errors.createError(ErrorType.Failed, "You must provide `intentConfiguration.confirmHandler` if you are not passing an intent client secret"))
166
+ return
167
+ }
168
+ let captureMethodString = intentConfiguration["captureMethod"] as? String
169
+ let intentConfig = buildIntentConfiguration(
170
+ modeParams: modeParams,
171
+ paymentMethodTypes: intentConfiguration["paymentMethodTypes"] as? [String],
172
+ captureMethod: mapCaptureMethod(captureMethodString)
173
+ )
174
+
175
+ if params["customFlow"] as? Bool == true {
176
+ PaymentSheet.FlowController.create(intentConfiguration: intentConfig, configuration: configuration) { [weak self] result in
177
+ handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self)
178
+ }
179
+ } else {
180
+ self.paymentSheet = PaymentSheet(
181
+ intentConfiguration: intentConfig,
182
+ configuration: configuration
183
+ )
184
+ resolve([])
185
+ }
186
+ }
187
+ }
188
+
189
+ private func mapCaptureMethod(_ captureMethod: String?) -> PaymentSheet.IntentConfiguration.CaptureMethod {
190
+ if let captureMethod = captureMethod {
191
+ switch captureMethod {
192
+ case "Automatic": return PaymentSheet.IntentConfiguration.CaptureMethod.automatic
193
+ case "Manual": return PaymentSheet.IntentConfiguration.CaptureMethod.manual
194
+ case "AutomaticAsync": return PaymentSheet.IntentConfiguration.CaptureMethod.automaticAsync
195
+ default: return PaymentSheet.IntentConfiguration.CaptureMethod.automatic
196
+ }
197
+ }
198
+ return PaymentSheet.IntentConfiguration.CaptureMethod.automatic
199
+ }
200
+
201
+ private func buildIntentConfiguration(
202
+ modeParams: NSDictionary,
203
+ paymentMethodTypes: [String]?,
204
+ captureMethod: PaymentSheet.IntentConfiguration.CaptureMethod
205
+ ) -> PaymentSheet.IntentConfiguration {
206
+ var mode: PaymentSheet.IntentConfiguration.Mode
207
+ if let amount = modeParams["amount"] as? Int {
208
+ mode = PaymentSheet.IntentConfiguration.Mode.payment(
209
+ amount: amount,
210
+ currency: modeParams["currencyCode"] as? String ?? "",
211
+ setupFutureUsage: modeParams["setupFutureUsage"] != nil
212
+ ? (modeParams["setupFutureUsage"] as? String == "OffSession" ? .offSession : .onSession)
213
+ : nil,
214
+ captureMethod: captureMethod
215
+ )
216
+ } else {
217
+ mode = PaymentSheet.IntentConfiguration.Mode.setup(
218
+ currency: modeParams["currencyCode"] as? String,
219
+ setupFutureUsage: modeParams["setupFutureUsage"] as? String == "OffSession" ? .offSession : .onSession
220
+ )
150
221
  }
222
+
223
+ return PaymentSheet.IntentConfiguration.init(
224
+ mode: mode,
225
+ paymentMethodTypes: paymentMethodTypes,
226
+ confirmHandler: { paymentMethod, shouldSavePaymentMethod, intentCreationCallback in
227
+ if (self.hasEventListeners) {
228
+ self.paymentSheetIntentCreationCallback = intentCreationCallback
229
+ self.sendEvent(withName: "onConfirmHandlerCallback", body: [
230
+ "paymentMethod": Mappers.mapFromPaymentMethod(paymentMethod) ?? NSNull(),
231
+ "shouldSavePaymentMethod": shouldSavePaymentMethod
232
+ ])
233
+ } else {
234
+ RCTMakeAndLogError("Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues", nil, nil)
235
+ }
236
+ })
151
237
  }
152
238
 
153
- private func buildCustomerHandlersForPaymentSheet(applePayParams: NSDictionary, orderTrackingCallback: RCTResponseSenderBlock?) -> PaymentSheet.ApplePayConfiguration.Handlers? {
154
- if (applePayParams["request"] == nil && orderTrackingCallback == nil) {
239
+ private func buildCustomerHandlersForPaymentSheet(applePayParams: NSDictionary) -> PaymentSheet.ApplePayConfiguration.Handlers? {
240
+ if (applePayParams["request"] == nil) {
155
241
  return nil
156
242
  }
157
243
  return PaymentSheet.ApplePayConfiguration.Handlers(paymentRequestHandler: { request in
@@ -163,9 +249,13 @@ extension StripeSdk {
163
249
  }
164
250
  return request
165
251
  }, authorizationResultHandler: { result, completion in
166
- if let orderTrackingCallback = orderTrackingCallback {
167
- self.orderTrackingHandler = (result, completion)
168
- orderTrackingCallback(nil)
252
+ if applePayParams.object(forKey: "setOrderTracking") != nil {
253
+ if (self.hasEventListeners) {
254
+ self.orderTrackingHandler = (result, completion)
255
+ self.sendEvent(withName: "onOrderTrackingCallback", body: [:])
256
+ } else {
257
+ RCTMakeAndLogError("Order tracking is enabled, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues", nil, nil)
258
+ }
169
259
  } else {
170
260
  completion(result)
171
261
  }