@stripe/stripe-react-native 0.19.0 → 0.21.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 (115) hide show
  1. package/CHANGELOG.md +46 -5
  2. package/README.md +2 -2
  3. package/android/build.gradle +1 -2
  4. package/android/gradle.properties +1 -1
  5. package/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +6 -3
  6. package/android/src/main/java/com/reactnativestripesdk/CardFormView.kt +22 -7
  7. package/android/src/main/java/com/reactnativestripesdk/CollectBankAccountLauncherFragment.kt +1 -1
  8. package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetFragment.kt +5 -1
  9. package/android/src/main/java/com/reactnativestripesdk/GooglePayFragment.kt +1 -1
  10. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +2 -1
  11. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +10 -9
  12. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +11 -4
  13. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +27 -14
  14. package/android/src/main/java/com/reactnativestripesdk/StripeSdkPackage.kt +3 -1
  15. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherFragment.kt +111 -0
  16. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetEvent.kt +28 -0
  17. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetView.kt +178 -0
  18. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressSheetViewManager.kt +67 -0
  19. package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +3 -1
  20. package/ios/AddressSheet/AddressSheetUtils.swift +98 -0
  21. package/ios/AddressSheet/AddressSheetView.swift +131 -0
  22. package/ios/AddressSheet/AddressSheetViewManager.m +25 -0
  23. package/ios/AddressSheet/AddressSheetViewManager.swift +19 -0
  24. package/ios/ApplePayUtils.swift +1 -1
  25. package/ios/CardFieldView.swift +3 -3
  26. package/ios/FinancialConnections.swift +23 -22
  27. package/ios/Mappers.swift +10 -2
  28. package/ios/PaymentMethodFactory.swift +6 -7
  29. package/ios/PaymentSheetAppearance.swift +27 -26
  30. package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonManager.m +0 -0
  31. package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonManager.swift +0 -0
  32. package/ios/{pushprovisioning → PushProvisioning}/AddToWalletButtonView.swift +0 -0
  33. package/ios/{pushprovisioning → PushProvisioning}/PushProvisioningUtils.swift +0 -0
  34. package/ios/StripeSdk.m +5 -0
  35. package/ios/StripeSdk.swift +75 -27
  36. package/ios/Tests/AddressSheetUtilsTests.swift +279 -0
  37. package/jest/mock.js +2 -0
  38. package/lib/commonjs/NativeStripeSdk.js.map +1 -1
  39. package/lib/commonjs/components/AddressSheet.js +2 -0
  40. package/lib/commonjs/components/AddressSheet.js.map +1 -0
  41. package/lib/commonjs/functions.js +1 -1
  42. package/lib/commonjs/functions.js.map +1 -1
  43. package/lib/commonjs/hooks/usePaymentSheet.js +1 -1
  44. package/lib/commonjs/hooks/usePaymentSheet.js.map +1 -1
  45. package/lib/commonjs/hooks/useStripe.js +1 -1
  46. package/lib/commonjs/hooks/useStripe.js.map +1 -1
  47. package/lib/commonjs/index.js +1 -1
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/types/Errors.js +1 -1
  50. package/lib/commonjs/types/Errors.js.map +1 -1
  51. package/lib/commonjs/types/FinancialConnections.js.map +1 -1
  52. package/lib/commonjs/types/index.js +1 -1
  53. package/lib/commonjs/types/index.js.map +1 -1
  54. package/lib/module/NativeStripeSdk.js.map +1 -1
  55. package/lib/module/components/AddressSheet.js +2 -0
  56. package/lib/module/components/AddressSheet.js.map +1 -0
  57. package/lib/module/functions.js +1 -1
  58. package/lib/module/functions.js.map +1 -1
  59. package/lib/module/hooks/usePaymentSheet.js +1 -1
  60. package/lib/module/hooks/usePaymentSheet.js.map +1 -1
  61. package/lib/module/hooks/useStripe.js +1 -1
  62. package/lib/module/hooks/useStripe.js.map +1 -1
  63. package/lib/module/index.js +1 -1
  64. package/lib/module/index.js.map +1 -1
  65. package/lib/module/types/Errors.js +1 -1
  66. package/lib/module/types/Errors.js.map +1 -1
  67. package/lib/module/types/FinancialConnections.js.map +1 -1
  68. package/lib/module/types/index.js +1 -1
  69. package/lib/module/types/index.js.map +1 -1
  70. package/lib/typescript/src/NativeStripeSdk.d.ts +1 -0
  71. package/lib/typescript/src/components/AddressSheet.d.ts +53 -0
  72. package/lib/typescript/src/functions.d.ts +6 -0
  73. package/lib/typescript/src/hooks/usePaymentSheet.d.ts +6 -0
  74. package/lib/typescript/src/hooks/useStripe.d.ts +6 -0
  75. package/lib/typescript/src/index.d.ts +1 -0
  76. package/lib/typescript/src/types/Common.d.ts +12 -0
  77. package/lib/typescript/src/types/Errors.d.ts +4 -0
  78. package/lib/typescript/src/types/FinancialConnections.d.ts +2 -2
  79. package/lib/typescript/src/types/PaymentMethod.d.ts +2 -0
  80. package/lib/typescript/src/types/PaymentSheet.d.ts +24 -1
  81. package/lib/typescript/src/types/index.d.ts +3 -6
  82. package/package.json +1 -1
  83. package/src/NativeStripeSdk.tsx +1 -0
  84. package/src/components/AddressSheet.tsx +82 -0
  85. package/src/functions.ts +9 -0
  86. package/src/hooks/usePaymentSheet.tsx +14 -0
  87. package/src/hooks/useStripe.tsx +11 -0
  88. package/src/index.tsx +4 -1
  89. package/src/types/Common.ts +13 -0
  90. package/src/types/Errors.ts +5 -0
  91. package/src/types/FinancialConnections.ts +4 -4
  92. package/src/types/PaymentMethod.ts +2 -0
  93. package/src/types/PaymentSheet.ts +26 -1
  94. package/src/types/index.ts +5 -10
  95. package/stripe-react-native.podspec +6 -2
  96. package/android/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  97. package/android/.gradle/7.1/dependencies-accessors/gc.properties +0 -0
  98. package/android/.gradle/7.1/fileChanges/last-build.bin +0 -0
  99. package/android/.gradle/7.1/fileHashes/fileHashes.lock +0 -0
  100. package/android/.gradle/7.1/gc.properties +0 -0
  101. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  102. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  103. package/android/.gradle/checksums/checksums.lock +0 -0
  104. package/android/.gradle/vcs-1/gc.properties +0 -0
  105. package/android/.idea/gradle.xml +0 -13
  106. package/android/.idea/misc.xml +0 -9
  107. package/android/.idea/modules/android.iml +0 -18
  108. package/android/.idea/modules.xml +0 -8
  109. package/android/.idea/vcs.xml +0 -6
  110. package/android/local.properties +0 -8
  111. package/ios/StripeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  112. package/ios/StripeSdk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  113. package/ios/StripeSdk.xcodeproj/project.xcworkspace/xcuserdata/charliecruzan.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  114. package/ios/StripeSdk.xcodeproj/xcuserdata/charliecruzan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -22
  115. package/ios/StripeSdk.xcodeproj/xcuserdata/charliecruzan.xcuserdatad/xcschemes/xcschememanagement.plist +0 -27
@@ -0,0 +1,111 @@
1
+ package com.reactnativestripesdk.addresssheet
2
+
3
+ import android.os.Bundle
4
+ import android.view.LayoutInflater
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.FrameLayout
8
+ import androidx.appcompat.app.AppCompatActivity
9
+ import androidx.fragment.app.Fragment
10
+ import com.facebook.react.bridge.ReactContext
11
+ import com.facebook.react.bridge.WritableMap
12
+ import com.reactnativestripesdk.utils.ErrorType
13
+ import com.reactnativestripesdk.utils.createError
14
+ import com.stripe.android.paymentsheet.PaymentSheet
15
+ import com.stripe.android.paymentsheet.addresselement.AddressDetails
16
+ import com.stripe.android.paymentsheet.addresselement.AddressLauncher
17
+ import com.stripe.android.paymentsheet.addresselement.AddressLauncherResult
18
+
19
+ class AddressLauncherFragment : Fragment() {
20
+ companion object {
21
+ internal var publishableKey: String? = null
22
+ internal const val TAG = "address_launcher_fragment"
23
+ }
24
+
25
+ private lateinit var addressLauncher: AddressLauncher
26
+ private var configuration = AddressLauncher.Configuration()
27
+ private var callback: ((error: WritableMap?, address: AddressDetails?) -> Unit)? = null
28
+
29
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
30
+ savedInstanceState: Bundle?): View {
31
+ return FrameLayout(requireActivity()).also {
32
+ it.visibility = View.GONE
33
+ }
34
+ }
35
+
36
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
37
+ publishableKey?.let { publishableKey ->
38
+ addressLauncher = AddressLauncher(this,
39
+ ::onAddressLauncherResult).also {
40
+ it.present(
41
+ publishableKey = publishableKey,
42
+ configuration = configuration
43
+ )
44
+ }
45
+ } ?: run {
46
+ callback?.invoke(
47
+ createError(ErrorType.Failed.toString(), "No publishable key set. Stripe has not been initialized. Initialize Stripe in your app with the StripeProvider component or the initStripe method."),
48
+ null
49
+ )
50
+ }
51
+ }
52
+
53
+ private fun onAddressLauncherResult(result: AddressLauncherResult) {
54
+ when (result) {
55
+ is AddressLauncherResult.Canceled -> {
56
+ callback?.invoke(
57
+ createError(ErrorType.Canceled.toString(), "The flow has been canceled."),
58
+ null
59
+ )
60
+ }
61
+ is AddressLauncherResult.Succeeded -> {
62
+ callback?.invoke(
63
+ null,
64
+ result.address
65
+ )
66
+ }
67
+ }
68
+ }
69
+
70
+ fun presentAddressSheet(
71
+ context: ReactContext,
72
+ appearance: PaymentSheet.Appearance,
73
+ defaultAddress: AddressDetails?,
74
+ allowedCountries: Set<String>,
75
+ buttonTitle: String?,
76
+ title: String?,
77
+ googlePlacesApiKey: String?,
78
+ autocompleteCountries: Set<String>,
79
+ additionalFields: AddressLauncher.AdditionalFieldsConfiguration?,
80
+ callback: ((error: WritableMap?, address: AddressDetails?) -> Unit)) {
81
+ configuration = AddressLauncher.Configuration(
82
+ appearance = appearance,
83
+ address = defaultAddress,
84
+ allowedCountries = allowedCountries,
85
+ buttonTitle = buttonTitle,
86
+ additionalFields = additionalFields,
87
+ title = title,
88
+ googlePlacesApiKey = googlePlacesApiKey,
89
+ autocompleteCountries = autocompleteCountries,
90
+ )
91
+ this.callback = callback
92
+ (context.currentActivity as? AppCompatActivity)?.let {
93
+ attemptToCleanupPreviousFragment(it)
94
+ commitFragmentAndStartFlow(it)
95
+ }
96
+ }
97
+
98
+ private fun attemptToCleanupPreviousFragment(currentActivity: AppCompatActivity) {
99
+ currentActivity.supportFragmentManager.beginTransaction()
100
+ .remove(this)
101
+ .commitAllowingStateLoss()
102
+ }
103
+
104
+ private fun commitFragmentAndStartFlow(currentActivity: AppCompatActivity) {
105
+ try {
106
+ currentActivity.supportFragmentManager.beginTransaction()
107
+ .add(this, TAG)
108
+ .commit()
109
+ } catch (_: IllegalStateException) {}
110
+ }
111
+ }
@@ -0,0 +1,28 @@
1
+ package com.reactnativestripesdk.addresssheet
2
+
3
+ import com.facebook.react.bridge.WritableMap
4
+ import com.facebook.react.uimanager.events.Event
5
+ import com.facebook.react.uimanager.events.RCTEventEmitter
6
+
7
+ internal class AddressSheetEvent constructor(viewTag: Int, private val eventType: EventType, private val eventMap: WritableMap?) : Event<AddressSheetEvent>(viewTag) {
8
+ enum class EventType {
9
+ OnSubmit,
10
+ OnError
11
+ }
12
+
13
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
14
+ rctEventEmitter.receiveEvent(viewTag, eventName, eventMap)
15
+ }
16
+
17
+ companion object {
18
+ const val ON_SUBMIT = "onSubmitAction"
19
+ const val ON_ERROR = "onErrorAction"
20
+ }
21
+
22
+ override fun getEventName(): String {
23
+ return when (eventType) {
24
+ EventType.OnSubmit -> ON_SUBMIT
25
+ EventType.OnError -> ON_ERROR
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,178 @@
1
+ package com.reactnativestripesdk.addresssheet
2
+
3
+ import android.os.Bundle
4
+ import android.util.Log
5
+ import android.widget.FrameLayout
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReadableMap
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.bridge.WritableNativeMap
10
+ import com.facebook.react.uimanager.ThemedReactContext
11
+ import com.facebook.react.uimanager.UIManagerModule
12
+ import com.facebook.react.uimanager.events.EventDispatcher
13
+ import com.reactnativestripesdk.buildPaymentSheetAppearance
14
+ import com.reactnativestripesdk.utils.ErrorType
15
+ import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
16
+ import com.reactnativestripesdk.utils.createError
17
+ import com.reactnativestripesdk.utils.toBundleObject
18
+ import com.stripe.android.paymentsheet.PaymentSheet
19
+ import com.stripe.android.paymentsheet.addresselement.AddressDetails
20
+ import com.stripe.android.paymentsheet.addresselement.AddressLauncher
21
+ import com.stripe.android.paymentsheet.addresselement.AddressLauncherResult
22
+
23
+ class AddressSheetView(private val context: ThemedReactContext) : FrameLayout(context) {
24
+ private var eventDispatcher: EventDispatcher? = context.getNativeModule(UIManagerModule::class.java)?.eventDispatcher
25
+ private var isVisible = false
26
+ private var appearanceParams: ReadableMap? = null
27
+ private var defaultAddress: AddressDetails? = null
28
+ private var allowedCountries: Set<String> = emptySet()
29
+ private var buttonTitle: String? = null
30
+ private var sheetTitle: String? = null
31
+ private var googlePlacesApiKey: String? = null
32
+ private var autocompleteCountries: Set<String> = emptySet()
33
+ private var additionalFields: AddressLauncher.AdditionalFieldsConfiguration? = null
34
+
35
+ private fun onSubmit(params: WritableMap) {
36
+ eventDispatcher?.dispatchEvent(
37
+ AddressSheetEvent(id, AddressSheetEvent.EventType.OnSubmit, params)
38
+ )
39
+ }
40
+
41
+ private fun onError(params: WritableMap?) {
42
+ eventDispatcher?.dispatchEvent(
43
+ AddressSheetEvent(id, AddressSheetEvent.EventType.OnError, params)
44
+ )
45
+ }
46
+
47
+ fun setVisible(newVisibility: Boolean) {
48
+ if (newVisibility && !isVisible) {
49
+ launchAddressSheet()
50
+ } else if (!newVisibility && isVisible) {
51
+ Log.w("StripeReactNative", "Programmatically dismissing the Address Sheet is not supported on Android.")
52
+ }
53
+ isVisible = newVisibility
54
+ }
55
+
56
+ private fun launchAddressSheet() {
57
+ val appearance = try {
58
+ buildPaymentSheetAppearance(toBundleObject(appearanceParams), context)
59
+ } catch (error: PaymentSheetAppearanceException) {
60
+ onError(createError(ErrorType.Failed.toString(), error))
61
+ return
62
+ }
63
+ AddressLauncherFragment().presentAddressSheet(
64
+ context,
65
+ appearance,
66
+ defaultAddress,
67
+ allowedCountries,
68
+ buttonTitle,
69
+ sheetTitle,
70
+ googlePlacesApiKey,
71
+ autocompleteCountries,
72
+ additionalFields
73
+ ) { error, address ->
74
+ if (address != null) {
75
+ onSubmit(buildResult(address))
76
+ } else {
77
+ onError(error)
78
+ }
79
+ isVisible = false
80
+ }
81
+ }
82
+
83
+ fun setAppearance(appearanceParams: ReadableMap) {
84
+ this.appearanceParams = appearanceParams
85
+ }
86
+
87
+ fun setDefaultValues(defaults: ReadableMap) {
88
+ defaultAddress = buildAddressDetails(defaults)
89
+ }
90
+
91
+ fun setAdditionalFields(fields: ReadableMap) {
92
+ additionalFields = buildAdditionalFieldsConfiguration(fields)
93
+ }
94
+
95
+ fun setAllowedCountries(countries: List<String>) {
96
+ allowedCountries = countries.toSet()
97
+ }
98
+
99
+ fun setAutocompleteCountries(countries: List<String>) {
100
+ autocompleteCountries = countries.toSet()
101
+ }
102
+
103
+ fun setPrimaryButtonTitle(title: String) {
104
+ buttonTitle = title
105
+ }
106
+
107
+ fun setSheetTitle(title: String) {
108
+ sheetTitle = title
109
+ }
110
+
111
+ fun setGooglePlacesApiKey(key: String) {
112
+ googlePlacesApiKey = key
113
+ }
114
+
115
+ companion object {
116
+ internal fun buildAddressDetails(bundle: Bundle): AddressDetails {
117
+ return AddressDetails(
118
+ name = bundle.getString("name"),
119
+ address = buildAddress(bundle.getBundle("address")),
120
+ phoneNumber = bundle.getString("phone"),
121
+ isCheckboxSelected = bundle.getBoolean("isCheckboxSelected"),
122
+ )
123
+ }
124
+
125
+ internal fun buildAddressDetails(map: ReadableMap): AddressDetails {
126
+ return buildAddressDetails(toBundleObject(map))
127
+ }
128
+
129
+ internal fun buildAddress(bundle: Bundle?): PaymentSheet.Address? {
130
+ if (bundle == null) {
131
+ return null
132
+ }
133
+ return PaymentSheet.Address(
134
+ city = bundle.getString("city"),
135
+ country = bundle.getString("country"),
136
+ line1 = bundle.getString("line1"),
137
+ line2 = bundle.getString("line2"),
138
+ state = bundle.getString("state"),
139
+ postalCode = bundle.getString("postalCode")
140
+ )
141
+ }
142
+
143
+ internal fun getFieldConfiguration(key: String?): AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration {
144
+ return when (key) {
145
+ "hidden" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.HIDDEN
146
+ "optional" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.OPTIONAL
147
+ "required" -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED
148
+ else -> AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.HIDDEN
149
+ }
150
+ }
151
+
152
+ internal fun buildAdditionalFieldsConfiguration(params: ReadableMap): AddressLauncher.AdditionalFieldsConfiguration {
153
+ val phoneConfiguration = getFieldConfiguration(params.getString("phoneNumber"))
154
+
155
+ return AddressLauncher.AdditionalFieldsConfiguration(
156
+ phone = phoneConfiguration,
157
+ checkboxLabel = params.getString("checkboxLabel")
158
+ )
159
+ }
160
+
161
+ internal fun buildResult(addressDetails: AddressDetails): WritableMap {
162
+ val result = WritableNativeMap()
163
+ result.putString("name", addressDetails.name)
164
+ WritableNativeMap().let {
165
+ it.putString("city", addressDetails.address?.city)
166
+ it.putString("country", addressDetails.address?.country)
167
+ it.putString("line1", addressDetails.address?.line1)
168
+ it.putString("line2", addressDetails.address?.line2)
169
+ it.putString("postalCode", addressDetails.address?.postalCode)
170
+ it.putString("state", addressDetails.address?.state)
171
+ result.putMap("address", it)
172
+ }
173
+ result.putString("phone", addressDetails.phoneNumber)
174
+ result.putBoolean("isCheckboxSelected", addressDetails.isCheckboxSelected ?: false)
175
+ return result
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,67 @@
1
+ package com.reactnativestripesdk.addresssheet
2
+
3
+ import com.facebook.react.bridge.ReadableArray
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.common.MapBuilder
6
+ import com.facebook.react.uimanager.SimpleViewManager
7
+ import com.facebook.react.uimanager.ThemedReactContext
8
+ import com.facebook.react.uimanager.annotations.ReactProp
9
+
10
+ class AddressSheetViewManager : SimpleViewManager<AddressSheetView>() {
11
+ override fun getName() = "AddressSheetView"
12
+
13
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
14
+ return MapBuilder.of(
15
+ AddressSheetEvent.ON_SUBMIT, MapBuilder.of("registrationName", "onSubmitAction"),
16
+ AddressSheetEvent.ON_ERROR, MapBuilder.of("registrationName", "onErrorAction"))
17
+ }
18
+
19
+ @ReactProp(name = "visible")
20
+ fun setVisible(view: AddressSheetView, visibility: Boolean) {
21
+ view.setVisible(visibility)
22
+ }
23
+
24
+ @ReactProp(name = "appearance")
25
+ fun setAppearance(view: AddressSheetView, appearance: ReadableMap) {
26
+ view.setAppearance(appearance)
27
+ }
28
+
29
+ @ReactProp(name = "defaultValues")
30
+ fun setDefaultValues(view: AddressSheetView, defaults: ReadableMap) {
31
+ view.setDefaultValues(defaults)
32
+ }
33
+
34
+ @ReactProp(name = "additionalFields")
35
+ fun setAdditionalFields(view: AddressSheetView, fields: ReadableMap) {
36
+ view.setAdditionalFields(fields)
37
+ }
38
+
39
+ @ReactProp(name = "allowedCountries")
40
+ fun setAllowedCountries(view: AddressSheetView, countries: ReadableArray) {
41
+ view.setAllowedCountries(countries.toArrayList().filterIsInstance<String>())
42
+ }
43
+
44
+ @ReactProp(name = "autocompleteCountries")
45
+ fun setAutocompleteCountries(view: AddressSheetView, countries: ReadableArray) {
46
+ view.setAutocompleteCountries(countries.toArrayList().filterIsInstance<String>())
47
+ }
48
+
49
+ @ReactProp(name = "primaryButtonTitle")
50
+ fun setPrimaryButtonTitle(view: AddressSheetView, title: String) {
51
+ view.setPrimaryButtonTitle(title)
52
+ }
53
+
54
+ @ReactProp(name = "sheetTitle")
55
+ fun setSheetTitle(view: AddressSheetView, title: String) {
56
+ view.setSheetTitle(title)
57
+ }
58
+
59
+ @ReactProp(name = "googlePlacesApiKey")
60
+ fun setGooglePlacesApiKey(view: AddressSheetView, key: String) {
61
+ view.setGooglePlacesApiKey(key)
62
+ }
63
+
64
+ override fun createViewInstance(reactContext: ThemedReactContext): AddressSheetView {
65
+ return AddressSheetView(reactContext)
66
+ }
67
+ }
@@ -347,6 +347,8 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
347
347
  card.putString("funding", paymentMethod.card?.funding)
348
348
  card.putString("last4", paymentMethod.card?.last4)
349
349
  card.putString("fingerprint", paymentMethod.card?.fingerprint)
350
+ card.putString("preferredNetwork", paymentMethod.card?.networks?.preferred)
351
+ card.putArray("availableNetworks", paymentMethod.card?.networks?.available?.toList() as? ReadableArray)
350
352
 
351
353
  sepaDebit.putString("bankCode", paymentMethod.sepaDebit?.bankCode)
352
354
  sepaDebit.putString("country", paymentMethod.sepaDebit?.country)
@@ -485,7 +487,7 @@ internal fun mapNextAction(type: NextActionType?, data: NextActionData?): Writab
485
487
  NextActionType.AlipayRedirect -> { // TODO: Can't access, private
486
488
  return null
487
489
  }
488
- NextActionType.BlikAuthorize, NextActionType.UseStripeSdk, null -> {
490
+ NextActionType.BlikAuthorize, NextActionType.UseStripeSdk, NextActionType.UpiAwaitNotification, null -> {
489
491
  return null
490
492
  }
491
493
  }
@@ -0,0 +1,98 @@
1
+ //
2
+ // AddressSheetUtils.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Charles Cruzan on 10/12/22.
6
+ //
7
+
8
+ import Foundation
9
+ import StripePaymentSheet
10
+
11
+ class AddressSheetUtils {
12
+ internal class func buildDefaultValues(params: NSDictionary?) -> AddressViewController.Configuration.DefaultAddressDetails {
13
+ guard let params = params else {
14
+ return AddressViewController.Configuration.DefaultAddressDetails()
15
+ }
16
+
17
+ return AddressViewController.Configuration.DefaultAddressDetails(
18
+ address: buildAddress(params: params["address"] as? NSDictionary),
19
+ name: params["name"] as? String,
20
+ phone: params["phone"] as? String,
21
+ isCheckboxSelected: params["isCheckboxSelected"] as? Bool
22
+ )
23
+ }
24
+
25
+ internal class func buildAddressDetails(params: NSDictionary?) -> AddressViewController.AddressDetails {
26
+ guard let params = params else { return AddressViewController.AddressDetails(address: buildAddress(params: nil)) }
27
+ return AddressViewController.AddressDetails(
28
+ address: buildAddress(params: params["address"] as? NSDictionary),
29
+ name: params["name"] as? String,
30
+ phone: params["phone"] as? String,
31
+ isCheckboxSelected: params["isCheckboxSelected"] as? Bool)
32
+ }
33
+
34
+ internal class func buildAddress(params: NSDictionary?) -> PaymentSheet.Address {
35
+ guard let params = params else { return PaymentSheet.Address() }
36
+ return PaymentSheet.Address(
37
+ city: params["city"] as? String,
38
+ country: params["country"] as? String,
39
+ line1: params["line1"] as? String,
40
+ line2: params["line2"] as? String,
41
+ postalCode: params["postalCode"] as? String,
42
+ state: params["state"] as? String
43
+ )
44
+ }
45
+
46
+ internal class func buildAddress(params: NSDictionary?) -> AddressViewController.AddressDetails.Address {
47
+ guard let params = params else { return AddressViewController.AddressDetails.Address(country: "", line1: "") }
48
+ return AddressViewController.AddressDetails.Address(
49
+ city: params["city"] as? String,
50
+ country: params["country"] as? String ?? "",
51
+ line1: params["line1"] as? String ?? "",
52
+ line2: params["line2"] as? String,
53
+ postalCode: params["postalCode"] as? String,
54
+ state: params["state"] as? String
55
+ )
56
+ }
57
+
58
+ internal class func buildAdditionalFieldsConfiguration(params: NSDictionary?) -> AddressViewController.Configuration.AdditionalFields {
59
+ guard let params = params else {
60
+ return AddressViewController.Configuration.AdditionalFields(phone: .hidden, checkboxLabel: nil)
61
+ }
62
+
63
+ return AddressViewController.Configuration.AdditionalFields(
64
+ phone: getFieldConfiguration(input: params["phoneNumber"] as? String, default: .hidden),
65
+ checkboxLabel: params["checkboxLabel"] as? String
66
+ )
67
+ }
68
+
69
+ internal class func getFieldConfiguration(input: String?, default: AddressViewController.Configuration.AdditionalFields.FieldConfiguration) -> AddressViewController.Configuration.AdditionalFields.FieldConfiguration {
70
+ switch (input) {
71
+ case "optional":
72
+ return .optional
73
+ case "required":
74
+ return .required
75
+ case "hidden":
76
+ return .hidden
77
+ default:
78
+ return `default`
79
+ }
80
+ }
81
+
82
+ internal class func buildResult(address: AddressViewController.AddressDetails) -> [AnyHashable : Any] {
83
+ return [
84
+ "name": address.name ?? NSNull(),
85
+ "address": [
86
+ "country": address.address.country,
87
+ "state": address.address.state,
88
+ "line1": address.address.line1,
89
+ "line2": address.address.line2,
90
+ "postalCode": address.address.postalCode,
91
+ "city": address.address.city,
92
+ ],
93
+ "phone": address.phone ?? NSNull(),
94
+ "isCheckboxSelected": address.isCheckboxSelected ?? NSNull(),
95
+ ] as [AnyHashable : Any]
96
+ }
97
+
98
+ }
@@ -0,0 +1,131 @@
1
+ //
2
+ // AddressSheetView.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Charles Cruzan on 10/11/22.
6
+ //
7
+
8
+ import Foundation
9
+ import StripePaymentSheet
10
+
11
+ @objc(AddressSheetView)
12
+ class AddressSheetView: UIView {
13
+ @objc var visible = false
14
+ @objc var presentationStyle: String = "popover"
15
+ @objc var animationStyle: String = ""
16
+ @objc var appearance: NSDictionary? = nil
17
+ @objc var defaultValues: NSDictionary? = nil
18
+ @objc var additionalFields: NSDictionary? = nil
19
+ @objc var allowedCountries: [String] = []
20
+ @objc var autocompleteCountries: [String] = []
21
+ @objc var primaryButtonTitle: String? = nil
22
+ @objc var sheetTitle: String? = nil
23
+ @objc var onSubmitAction: RCTDirectEventBlock?
24
+ @objc var onErrorAction: RCTDirectEventBlock?
25
+
26
+ private var wasVisible = false
27
+ private var addressViewController: AddressViewController? = nil
28
+ internal var addressDetails: AddressViewController.AddressDetails? = nil
29
+
30
+ override init(frame: CGRect) {
31
+ super.init(frame: frame)
32
+ }
33
+
34
+ required init?(coder: NSCoder) {
35
+ fatalError("init(coder:) has not been implemented")
36
+ }
37
+
38
+ override func didSetProps(_ changedProps: [String]!) {
39
+ if (visible && !wasVisible) {
40
+ presentAddressSheet()
41
+ wasVisible = true
42
+ } else if (!visible && wasVisible) {
43
+ addressViewController?.dismiss(animated: true)
44
+ wasVisible = false
45
+ }
46
+ }
47
+
48
+ private func presentAddressSheet() {
49
+ if (STPAPIClient.shared.publishableKey == nil) {
50
+ onErrorAction!(
51
+ Errors.createError(ErrorType.Failed, "No publishable key set. Stripe has not been initialized. Initialize Stripe in your app with the StripeProvider component or the initStripe method.") as? [AnyHashable : Any]
52
+ )
53
+ return
54
+ }
55
+ var config: AddressViewController.Configuration
56
+ do {
57
+ config = try buildAddressSheetConfiguration()
58
+ } catch {
59
+ onErrorAction!(
60
+ Errors.createError(ErrorType.Failed, error.localizedDescription) as? [AnyHashable : Any]
61
+ )
62
+ return
63
+ }
64
+
65
+ self.addressViewController = AddressViewController(
66
+ configuration: config,
67
+ delegate: self
68
+ )
69
+
70
+ let navigationController = UINavigationController(rootViewController: addressViewController!)
71
+ navigationController.modalPresentationStyle = getModalPresentationStyle()
72
+ navigationController.modalTransitionStyle = getModalTransitionStyle()
73
+ let vc = findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController())
74
+ vc.present(navigationController, animated: true)
75
+ }
76
+
77
+ private func buildAddressSheetConfiguration() throws -> AddressViewController.Configuration {
78
+ let appearanceConfiguration = try PaymentSheetAppearance.buildAppearanceFromParams(userParams: appearance)
79
+
80
+ return AddressViewController.Configuration(
81
+ defaultValues: AddressSheetUtils.buildDefaultValues(params: defaultValues),
82
+ additionalFields: AddressSheetUtils.buildAdditionalFieldsConfiguration(params: additionalFields),
83
+ allowedCountries: allowedCountries,
84
+ appearance: appearanceConfiguration,
85
+ buttonTitle: primaryButtonTitle,
86
+ title: sheetTitle
87
+ )
88
+ }
89
+
90
+ private func getModalPresentationStyle() -> UIModalPresentationStyle {
91
+ switch (presentationStyle) {
92
+ case "fullscreen":
93
+ return .fullScreen
94
+ case "popover":
95
+ fallthrough
96
+ default:
97
+ return .popover
98
+ }
99
+ }
100
+
101
+ private func getModalTransitionStyle() -> UIModalTransitionStyle {
102
+ switch (animationStyle) {
103
+ case "flip":
104
+ return .flipHorizontal
105
+ case "curl":
106
+ return .partialCurl
107
+ case "dissolve":
108
+ return .crossDissolve
109
+ case "slide":
110
+ fallthrough
111
+ default:
112
+ return .coverVertical
113
+ }
114
+ }
115
+ }
116
+
117
+ extension AddressSheetView: AddressViewControllerDelegate {
118
+ func addressViewControllerDidFinish(_ addressViewController: AddressViewController, with address: AddressViewController.AddressDetails?) {
119
+ guard let address = address else {
120
+ onErrorAction!(
121
+ Errors.createError(
122
+ ErrorType.Canceled,
123
+ "The flow has been canceled."
124
+ ) as? [AnyHashable : Any]
125
+ )
126
+ return
127
+ }
128
+ self.addressDetails = address
129
+ onSubmitAction!(AddressSheetUtils.buildResult(address: address))
130
+ }
131
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // AddressSheetViewManager.m
3
+ // stripe-react-native
4
+ //
5
+ // Created by Charles Cruzan on 10/11/22.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #import <React/RCTBridgeModule.h>
10
+ #import <React/RCTViewManager.h>
11
+
12
+ @interface RCT_EXTERN_MODULE(AddressSheetViewManager, RCTViewManager)
13
+ RCT_EXPORT_VIEW_PROPERTY(visible, BOOL)
14
+ RCT_EXPORT_VIEW_PROPERTY(presentationStyle, NSString)
15
+ RCT_EXPORT_VIEW_PROPERTY(animationStyle, NSString)
16
+ RCT_EXPORT_VIEW_PROPERTY(appearance, NSDictionary)
17
+ RCT_EXPORT_VIEW_PROPERTY(defaultValues, NSDictionary)
18
+ RCT_EXPORT_VIEW_PROPERTY(additionalFields, NSDictionary)
19
+ RCT_EXPORT_VIEW_PROPERTY(allowedCountries, NSArray)
20
+ RCT_EXPORT_VIEW_PROPERTY(autocompleteCountries, NSArray)
21
+ RCT_EXPORT_VIEW_PROPERTY(primaryButtonTitle, NSString)
22
+ RCT_EXPORT_VIEW_PROPERTY(sheetTitle, NSString)
23
+ RCT_EXPORT_VIEW_PROPERTY(onSubmitAction, RCTDirectEventBlock)
24
+ RCT_EXPORT_VIEW_PROPERTY(onErrorAction, RCTDirectEventBlock)
25
+ @end
@@ -0,0 +1,19 @@
1
+ //
2
+ // AddressSheetViewManager.swift
3
+ // stripe-react-native
4
+ //
5
+ // Created by Charles Cruzan on 10/11/22.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ @objc(AddressSheetViewManager)
11
+ class AddressSheetViewManager : RCTViewManager {
12
+ override func view() -> UIView! {
13
+ return AddressSheetView()
14
+ }
15
+
16
+ override class func requiresMainQueueSetup() -> Bool {
17
+ return true
18
+ }
19
+ }
@@ -6,7 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
- import Stripe
9
+ import StripePaymentSheet
10
10
 
11
11
  class ApplePayUtils {
12
12