diff --git a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt index 0b8c620b..8d9a7432 100644 --- a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt +++ b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt @@ -146,7 +146,7 @@ internal fun mapToDiscoveryMethod(method: String?): DiscoveryMethod? { } } -internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent): ReadableMap = nativeMapOf { +internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent, uuid: String): ReadableMap = nativeMapOf { putInt("amount", paymentIntent.amount.toInt()) putString("currency", paymentIntent.currency) putString("id", paymentIntent.id) @@ -154,9 +154,10 @@ internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent): ReadableMap = n putString("status", mapFromPaymentIntentStatus(paymentIntent.status)) putArray("charges", mapFromChargesList(paymentIntent.getCharges())) putString("created", convertToUnixTimestamp(paymentIntent.created)) + putString("sdk_uuid", uuid) } -internal fun mapFromSetupIntent(setupIntent: SetupIntent): ReadableMap = nativeMapOf { +internal fun mapFromSetupIntent(setupIntent: SetupIntent, uuid: String): ReadableMap = nativeMapOf { putString("created", convertToUnixTimestamp(setupIntent.created)) putString("id", setupIntent.id) putString("status", mapFromSetupIntentStatus(setupIntent.status)) @@ -169,6 +170,7 @@ internal fun mapFromSetupIntent(setupIntent: SetupIntent): ReadableMap = nativeM putString("onBehalfOfId", setupIntent.onBehalfOfId) putString("paymentMethodId", setupIntent.paymentMethodId) putString("singleUseMandateId", setupIntent.singleUseMandateId) + putString("sdk_uuid", uuid) } internal fun mapFromSetupAttempt(attempt: SetupAttempt?): ReadableMap? = attempt?.let { diff --git a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt index b9f20aca..82ed1fe8 100644 --- a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt +++ b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt @@ -1,5 +1,6 @@ package com.stripeterminalreactnative +import android.annotation.SuppressLint import android.app.Application import android.content.ComponentCallbacks2 import android.content.res.Configuration @@ -51,6 +52,8 @@ import com.stripeterminalreactnative.listener.RNUsbReaderListener import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.util.UUID +import kotlin.collections.HashMap class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @@ -61,7 +64,6 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : private var collectRefundPaymentMethodCancelable: Cancelable? = null private var collectSetupIntentCancelable: Cancelable? = null private var installUpdateCancelable: Cancelable? = null - private var readReusableCardCancelable: Cancelable? = null private var cancelReaderConnectionCancellable: Cancelable? = null private var paymentIntents: HashMap = HashMap() @@ -160,6 +162,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : promise.resolve(null) } + @SuppressLint("MissingPermission") @ReactMethod @Suppress("unused") fun discoverReaders(params: ReadableMap, promise: Promise) = withExceptionResolver(promise) { @@ -396,8 +399,10 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : } } - terminal.createPaymentIntent(intentParams.build(), RNPaymentIntentCallback(promise) { pi -> - (pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi } + val uuid = UUID.randomUUID().toString() + + terminal.createPaymentIntent(intentParams.build(), RNPaymentIntentCallback(promise, uuid) { pi -> + paymentIntents[uuid] = pi }) } @@ -406,11 +411,14 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @Suppress("unused") fun collectPaymentMethod(params: ReadableMap, promise: Promise) = withExceptionResolver(promise) { - val paymentIntentId = requireParam(params.getString("paymentIntentId")) { - "You must provide a paymentIntentId" + val paymentIntentJson = requireParam(params.getMap("paymentIntent")) { + "You must provide a paymentIntent" + } + val uuid = requireParam(paymentIntentJson.getString("sdk_uuid")) { + "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent." } - val paymentIntent = requireParam(paymentIntents[paymentIntentId]) { - "There is no associated paymentIntent with id $paymentIntentId" + val paymentIntent = requireParam(paymentIntents[uuid]) { + "No PaymentIntent was found with the sdk_uuid $uuid. The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent." } val configBuilder = CollectConfiguration.Builder() @@ -432,8 +440,8 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : collectPaymentMethodCancelable = terminal.collectPaymentMethod( paymentIntent, - RNPaymentIntentCallback(promise) { pi -> - (pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi } + RNPaymentIntentCallback(promise, uuid) { pi -> + paymentIntents[uuid] = pi }, config ) @@ -443,19 +451,23 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @ReactMethod @Suppress("unused") fun retrievePaymentIntent(clientSecret: String, promise: Promise) { - terminal.retrievePaymentIntent(clientSecret, RNPaymentIntentCallback(promise) { pi -> - (pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi } + val uuid = UUID.randomUUID().toString() + terminal.retrievePaymentIntent(clientSecret, RNPaymentIntentCallback(promise, uuid) { pi -> + paymentIntents[uuid] = pi }) } @ReactMethod @Suppress("unused") - fun confirmPaymentIntent(paymentIntentId: String, promise: Promise) = withExceptionResolver(promise) { - val paymentIntent = requireParam(paymentIntents[paymentIntentId]) { - "There is no associated paymentIntent with id $paymentIntentId" + fun confirmPaymentIntent(paymentIntent: ReadableMap, promise: Promise) = withExceptionResolver(promise) { + val uuid = requireParam(paymentIntent.getString("sdk_uuid")) { + "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent." + } + val paymentIntent = requireParam(paymentIntents[uuid]) { + "No PaymentIntent was found with the sdk_uuid $uuid. The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent." } - terminal.confirmPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise) { + terminal.confirmPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise, uuid) { paymentIntents.clear() }) } @@ -478,55 +490,61 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : SetupIntentParameters.Builder().setCustomer(customerId).build() } ?: SetupIntentParameters.NULL - terminal.createSetupIntent(intentParams, RNSetupIntentCallback(promise) { - setupIntents[it.id] = it + val uuid = UUID.randomUUID().toString() + terminal.createSetupIntent(intentParams, RNSetupIntentCallback(promise, uuid) { + setupIntents[uuid] = it }) } @ReactMethod @Suppress("unused") fun retrieveSetupIntent(clientSecret: String, promise: Promise) { - terminal.retrieveSetupIntent(clientSecret, RNSetupIntentCallback(promise) { - setupIntents[it.id] = it + val uuid = UUID.randomUUID().toString() + terminal.retrieveSetupIntent(clientSecret, RNSetupIntentCallback(promise, uuid) { + setupIntents[uuid] = it }) } @OptIn(OfflineMode::class) @ReactMethod @Suppress("unused") - fun cancelPaymentIntent(paymentIntentId: String, promise: Promise) = + fun cancelPaymentIntent(paymentIntent: ReadableMap, promise: Promise) = withExceptionResolver(promise) { - val paymentIntent = requireParam(paymentIntents[paymentIntentId]) { - "There is no associated paymentIntent with id $paymentIntentId" + val uuid = requireParam(paymentIntent.getString("sdk_uuid")) { + "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent." + } + val paymentIntent = requireParam(paymentIntents[uuid]) { + "No PaymentIntent was found with the sdk_uuid $uuid. The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent." } - terminal.cancelPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise) { pi -> - (pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = null } + + terminal.cancelPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise, uuid) { + paymentIntents[uuid] = null }) } - @ReactMethod - @Suppress("unused") - fun cancelReadReusableCard(promise: Promise) { - cancelOperation(promise, readReusableCardCancelable, "readReusableCard") - } - @ReactMethod @Suppress("unused") fun collectSetupIntentPaymentMethod(params: ReadableMap, promise: Promise) = withExceptionResolver(promise) { - val setupIntentId = params.getString("setupIntentId") + val setupIntentJson = requireParam(params.getMap("setupIntent")) { + "You must provide a setupIntent" + } + val uuid = requireParam(setupIntentJson.getString("sdk_uuid")) { + "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent." + } + val setupIntent = requireParam(setupIntents[uuid]) { + "No SetupIntent was found with the sdk_uuid $uuid. The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent." + } + val customerConsentCollected = getBoolean(params, "customerConsentCollected") - val setupIntent = requireParam(setupIntents[setupIntentId]) { - "There is no created setupIntent with id $setupIntentId" - } collectSetupIntentCancelable = terminal.collectSetupIntentPaymentMethod( setupIntent, customerConsentCollected, SetupIntentConfiguration.Builder() .setEnableCustomerCancellation(false) .build(), - RNSetupIntentCallback(promise) { setupIntents[it.id] = it } + RNSetupIntentCallback(promise, uuid) { setupIntents[uuid] = it } ) } @@ -571,28 +589,34 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @ReactMethod @Suppress("unused") - fun cancelSetupIntent(setupIntentId: String, promise: Promise) = + fun cancelSetupIntent(setupIntent: ReadableMap, promise: Promise) = withExceptionResolver(promise) { - val setupIntent = requireParam(setupIntents[setupIntentId]) { - "There is no associated setupIntent with id $setupIntentId" + val uuid = requireParam(setupIntent.getString("sdk_uuid")) { + "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent." + } + val setupIntent = requireParam(setupIntents[uuid]) { + "No SetupIntent was found with the sdk_uuid $uuid. The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent." } val params = SetupIntentCancellationParameters.Builder().build() - terminal.cancelSetupIntent(setupIntent, params, RNSetupIntentCallback(promise) { + terminal.cancelSetupIntent(setupIntent, params, RNSetupIntentCallback(promise, uuid) { setupIntents[setupIntent.id] = null }) } @ReactMethod @Suppress("unused") - fun confirmSetupIntent(setupIntentId: String, promise: Promise) = + fun confirmSetupIntent(setupIntent: ReadableMap, promise: Promise) = withExceptionResolver(promise) { - val setupIntent = requireParam(setupIntents[setupIntentId]) { - "There is no associated setupIntent with id $setupIntentId" + val uuid = requireParam(setupIntent.getString("sdk_uuid")) { + "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent." + } + val setupIntent = requireParam(setupIntents[uuid]) { + "No SetupIntent was found with the sdk_uuid $uuid. The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent." } - terminal.confirmSetupIntent(setupIntent, RNSetupIntentCallback(promise) { + terminal.confirmSetupIntent(setupIntent, RNSetupIntentCallback(promise, uuid) { setupIntents[it.id] = null }) } diff --git a/android/src/main/java/com/stripeterminalreactnative/callback/RNPaymentIntentCallback.kt b/android/src/main/java/com/stripeterminalreactnative/callback/RNPaymentIntentCallback.kt index 7113effa..caaf06b8 100644 --- a/android/src/main/java/com/stripeterminalreactnative/callback/RNPaymentIntentCallback.kt +++ b/android/src/main/java/com/stripeterminalreactnative/callback/RNPaymentIntentCallback.kt @@ -10,13 +10,14 @@ import com.stripeterminalreactnative.nativeMapOf class RNPaymentIntentCallback( private val promise: Promise, + private val uuid: String, private val onPaymentIntentSuccess: (PaymentIntent) -> Unit = {} ): PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { onPaymentIntentSuccess(paymentIntent) promise.resolve(nativeMapOf { - putMap("paymentIntent", mapFromPaymentIntent(paymentIntent)) + putMap("paymentIntent", mapFromPaymentIntent(paymentIntent, uuid)) }) } diff --git a/android/src/main/java/com/stripeterminalreactnative/callback/RNSetupIntentCallback.kt b/android/src/main/java/com/stripeterminalreactnative/callback/RNSetupIntentCallback.kt index 5346c900..9049e12c 100644 --- a/android/src/main/java/com/stripeterminalreactnative/callback/RNSetupIntentCallback.kt +++ b/android/src/main/java/com/stripeterminalreactnative/callback/RNSetupIntentCallback.kt @@ -10,13 +10,14 @@ import com.stripeterminalreactnative.nativeMapOf class RNSetupIntentCallback( private val promise: Promise, + private val uuid: String, private val onSetupIntentSuccess: (SetupIntent) -> Unit = {} ): SetupIntentCallback { override fun onSuccess(setupIntent: SetupIntent) { onSetupIntentSuccess(setupIntent) promise.resolve(nativeMapOf { - putMap("setupIntent", mapFromSetupIntent(setupIntent)) + putMap("setupIntent", mapFromSetupIntent(setupIntent, uuid)) }) } diff --git a/bitrise.yml b/bitrise.yml index 9790d15f..b6f17bee 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -97,7 +97,7 @@ workflows: - content: |- set -e # This is a terrible hack, as I haven't worked out how Bitrise's `pod install` step interacts with the rbenv set in this app. You definitely shouldn't copy this. - cd dev-app/ios && asdf install ruby 2.7.4 && bundle install && \ + cd dev-app/ios && asdf install ruby 3.2.2 && bundle install && \ gem install cocoapods -v 1.12.1 && pod install && cd - && \ echo "Checking for diffs in pod lockfile, if this fails please ensure all dependencies are up to date" && \ git diff --exit-code diff --git a/dev-app/.ruby-version b/dev-app/.ruby-version index a4dd9dba..be94e6f5 100644 --- a/dev-app/.ruby-version +++ b/dev-app/.ruby-version @@ -1 +1 @@ -2.7.4 +3.2.2 diff --git a/dev-app/Gemfile b/dev-app/Gemfile index e870d0fa..c94d5f74 100644 --- a/dev-app/Gemfile +++ b/dev-app/Gemfile @@ -1,4 +1,5 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby '2.7.4' +ruby '3.2.2' gem 'cocoapods', '~> 1.11', '>= 1.12.1' +gem 'activesupport', '~> 7.0', '<= 7.0.8' diff --git a/dev-app/Gemfile.lock b/dev-app/Gemfile.lock index 049b4b5a..0bc747f9 100644 --- a/dev-app/Gemfile.lock +++ b/dev-app/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.7.2) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -65,7 +65,7 @@ GEM i18n (1.14.1) concurrent-ruby (~> 1.0) json (2.6.3) - minitest (5.19.0) + minitest (5.20.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) @@ -89,10 +89,11 @@ PLATFORMS ruby DEPENDENCIES + activesupport (~> 7.0, <= 7.0.8) cocoapods (~> 1.11, >= 1.12.1) RUBY VERSION - ruby 2.7.4p191 + ruby 3.2.2p53 BUNDLED WITH 2.1.4 diff --git a/dev-app/src/api/api.ts b/dev-app/src/api/api.ts index d247044d..27b63964 100644 --- a/dev-app/src/api/api.ts +++ b/dev-app/src/api/api.ts @@ -219,7 +219,6 @@ export class Api { Authorization: `Bearer ${secretKey}`, }, }); - const data = await result.json(); if ('error' in data) { diff --git a/dev-app/src/screens/CollectCardPaymentScreen.tsx b/dev-app/src/screens/CollectCardPaymentScreen.tsx index 9148fd71..e2d95cf3 100644 --- a/dev-app/src/screens/CollectCardPaymentScreen.tsx +++ b/dev-app/src/screens/CollectCardPaymentScreen.tsx @@ -254,10 +254,10 @@ export default function CollectCardPaymentScreen() { ], }); - return await _collectPaymentMethod(paymentIntent.id); + return await _collectPaymentMethod(paymentIntent); }; - const _collectPaymentMethod = async (paymentIntentId: string) => { + const _collectPaymentMethod = async (pi: PaymentIntent.Type) => { // @ts-ignore setCancel((prev) => ({ ...prev, isDisabled: false })); addLogs({ @@ -266,13 +266,13 @@ export default function CollectCardPaymentScreen() { { name: 'Collect', description: 'terminal.collectPaymentMethod', - metadata: { paymentIntentId }, + metadata: { paymentIntentId: pi.id }, onBack: cancelCollectPaymentMethod, }, ], }); const { paymentIntent, error } = await collectPaymentMethod({ - paymentIntentId: paymentIntentId, + paymentIntent: pi, skipTipping: skipTipping, tipEligibleAmount: tipEligibleAmount ? Number(tipEligibleAmount) @@ -331,7 +331,7 @@ export default function CollectCardPaymentScreen() { }); const { paymentIntent, error } = await confirmPaymentIntent( - collectedPaymentIntent.id + collectedPaymentIntent ); if (error) { diff --git a/dev-app/src/screens/SetupIntentScreen.tsx b/dev-app/src/screens/SetupIntentScreen.tsx index 43a4f7ab..ee1ec882 100644 --- a/dev-app/src/screens/SetupIntentScreen.tsx +++ b/dev-app/src/screens/SetupIntentScreen.tsx @@ -53,18 +53,18 @@ export default function SetupIntentScreen() { }); const _confirmPaymentIntent = useCallback( - async (setupIntentId: string) => { + async (si: SetupIntent.Type) => { addLogs({ name: 'Process Payment', events: [ { name: 'Process', description: 'terminal.confirmSetupIntent', - metadata: { setupIntentId }, + metadata: { setupIntentId: si.id }, }, ], }); - const { setupIntent, error } = await confirmSetupIntent(setupIntentId); + const { setupIntent, error } = await confirmSetupIntent(si); if (error) { addLogs({ name: 'Process Payment', @@ -96,20 +96,20 @@ export default function SetupIntentScreen() { ); const _collectPaymentMethod = useCallback( - async (setupIntentId: string) => { + async (si: SetupIntent.Type) => { addLogs({ name: 'Collect Setup Intent', events: [ { name: 'Collect', description: 'terminal.collectSetupIntentPaymentMethod', - metadata: { setupIntentId }, + metadata: { setupIntentId: si.id }, onBack: cancelCollectSetupIntent, }, ], }); const { setupIntent, error } = await collectSetupIntentPaymentMethod({ - setupIntentId: setupIntentId, + setupIntent: si, customerConsentCollected: true, }); if (error) { @@ -137,7 +137,7 @@ export default function SetupIntentScreen() { }, ], }); - await _confirmPaymentIntent(setupIntentId); + await _confirmPaymentIntent(setupIntent); } }, [ @@ -251,7 +251,7 @@ export default function SetupIntentScreen() { ], }); } else if (setupIntent) { - await _collectPaymentMethod(setupIntent.id); + await _collectPaymentMethod(setupIntent); } }, [ api, diff --git a/ios/Mappers.swift b/ios/Mappers.swift index 3d41f8c1..d4a54fde 100644 --- a/ios/Mappers.swift +++ b/ios/Mappers.swift @@ -80,7 +80,7 @@ class Mappers { guard let displayName = cartLineItem["displayName"] as? String else { return nil } guard let quantity = cartLineItem["quantity"] as? NSNumber else { return nil } guard let amount = cartLineItem["amount"] as? NSNumber else { return nil } - + do { let lineItem = try CartLineItemBuilder(displayName: displayName) .setQuantity(Int(truncating: quantity)) @@ -136,8 +136,8 @@ class Mappers { } } - - class func mapFromPaymentIntent(_ paymentIntent: PaymentIntent) -> NSDictionary { + + class func mapFromPaymentIntent(_ paymentIntent: PaymentIntent, uuid: String) -> NSDictionary { let result: NSDictionary = [ "amount": paymentIntent.amount, "charges": mapFromCharges(paymentIntent.charges), @@ -145,13 +145,15 @@ class Mappers { "currency": paymentIntent.currency, "status": mapFromPaymentIntentStatus(paymentIntent.status), "id": paymentIntent.stripeId, + "sdk_uuid": uuid, ] return result } - class func mapFromSetupIntent(_ setupIntent: SetupIntent) -> NSDictionary { + class func mapFromSetupIntent(_ setupIntent: SetupIntent, uuid: String) -> NSDictionary { let result: NSDictionary = [ "id": setupIntent.stripeId, + "sdk_uuid": uuid, "created": convertDateToUnixTimestamp(date: setupIntent.created) ?? NSNull(), "status": mapFromSetupIntentStatus(setupIntent.status), "latestAttempt": mapFromSetupAttempt(setupIntent.latestAttempt) ?? NSNull(), diff --git a/ios/StripeTerminalReactNative.m b/ios/StripeTerminalReactNative.m index 842f45eb..d6570062 100644 --- a/ios/StripeTerminalReactNative.m +++ b/ios/StripeTerminalReactNative.m @@ -74,13 +74,13 @@ @interface RCT_EXTERN_MODULE(StripeTerminalReactNative, RCTEventEmitter) ) RCT_EXTERN_METHOD( - confirmPaymentIntent:(NSString *)paymentIntentId + confirmPaymentIntent:(NSDictionary *)paymentIntentJson resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) RCT_EXTERN_METHOD( - cancelPaymentIntent:(NSString *)paymentIntentId + cancelPaymentIntent:(NSDictionary *)paymentIntentJson resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) @@ -119,7 +119,7 @@ @interface RCT_EXTERN_MODULE(StripeTerminalReactNative, RCTEventEmitter) ) RCT_EXTERN_METHOD( - cancelSetupIntent:(NSString *)setupIntentId + cancelSetupIntent:(NSDictionary *)setupIntentJson resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) @@ -131,7 +131,7 @@ @interface RCT_EXTERN_MODULE(StripeTerminalReactNative, RCTEventEmitter) ) RCT_EXTERN_METHOD( - confirmSetupIntent:(NSString *)paymentIntentId + confirmSetupIntent:(NSDictionary *)setupIntentJson resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) diff --git a/ios/StripeTerminalReactNative.swift b/ios/StripeTerminalReactNative.swift index 1721cfab..0a65283c 100644 --- a/ios/StripeTerminalReactNative.swift +++ b/ios/StripeTerminalReactNative.swift @@ -138,23 +138,6 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } } - @objc(cancelReadReusableCard:rejecter:) - func cancelReadReusableCard(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let cancelable = readReusableCardCancelable else { - resolve(Errors.createError(code: ErrorCode.cancelFailedAlreadyCompleted, message: "readReusableCard could not be canceled because the command has already been canceled or has completed.")) - return - } - cancelable.cancel() { error in - if let error = error as NSError? { - resolve(Errors.createError(nsError: error)) - } - else { - resolve([:]) - } - self.readReusableCardCancelable = nil - } - } - @objc(simulateReaderUpdate:resolver:rejecter:) func simulateReaderUpdate(update: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void { Terminal.shared.simulatorConfiguration.availableReaderUpdate = Mappers.mapToSimulateReaderUpdate(update) @@ -323,7 +306,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe let onBehalfOf: String? = params["onBehalfOf"] as? String let merchantDisplayName: String? = params["merchantDisplayName"] as? String let tosAcceptancePermitted: Bool = params["tosAcceptancePermitted"] as? Bool ?? true - + let connectionConfig: LocalMobileConnectionConfiguration do { connectionConfig = try LocalMobileConnectionConfigurationBuilder(locationId: locationId ?? selectedReader.locationId ?? "") @@ -411,7 +394,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe default: break } - + let cardPresentParams: CardPresentParameters do { cardPresentParams = try cardPresentParamsBuilder.build() @@ -436,13 +419,14 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe resolve(Errors.createError(nsError: error as NSError)) return } - + Terminal.shared.createPaymentIntent(paymentParams) { pi, error in if let error = error as NSError? { resolve(Errors.createError(nsError: error)) } else if let pi = pi { - let paymentIntent = Mappers.mapFromPaymentIntent(pi) - self.paymentIntents[pi.stripeId] = pi + let uuid = UUID().uuidString + let paymentIntent = Mappers.mapFromPaymentIntent(pi, uuid: uuid) + self.paymentIntents[uuid] = pi resolve(["paymentIntent": paymentIntent]) } } @@ -464,8 +448,9 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = error as NSError? { resolve(Errors.createError(nsError: error)) } else if let si = si { - let setupIntent = Mappers.mapFromSetupIntent(si) - self.setupIntents[si.stripeId] = si + let uuid = UUID().uuidString + let setupIntent = Mappers.mapFromSetupIntent(si,uuid: uuid) + self.setupIntents[uuid] = si resolve(["setupIntent": setupIntent]) } } @@ -473,22 +458,26 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe @objc(collectPaymentMethod:resolver:rejecter:) func collectPaymentMethod(params: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let id = params["paymentIntentId"] as? String else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide paymentIntentId.")) + guard let paymentIntentJSON = params["paymentIntent"] as? NSDictionary else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide paymentIntent.")) return } - guard let paymentIntent = self.paymentIntents[Optional(id)] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no associated paymentIntent with id \(id)")) + guard let uuid = paymentIntentJSON["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) + return + } + guard let paymentIntent = self.paymentIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No PaymentIntent was found with the sdk_uuid \(uuid). The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent.")) return } let skipTipping = params["skipTipping"] as? Bool ?? false let updatePaymentIntent = params["updatePaymentIntent"] as? Bool ?? false - + let collectConfigBuilder = CollectConfigurationBuilder() .setSkipTipping(skipTipping) .setUpdatePaymentIntent(updatePaymentIntent) - + if let eligibleAmount = params["tipEligibleAmount"] as? Int { do { let tippingConfig = try TippingConfigurationBuilder() @@ -508,7 +497,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe resolve(Errors.createError(nsError: error as NSError)) return } - + self.collectPaymentMethodCancelable = Terminal.shared.collectPaymentMethod( paymentIntent, collectConfig: collectConfig @@ -516,7 +505,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = collectError as NSError? { resolve(Errors.createError(nsError: error)) } else if let paymentIntent = pi { - let paymentIntent = Mappers.mapFromPaymentIntent(paymentIntent) + let paymentIntent = Mappers.mapFromPaymentIntent(paymentIntent, uuid: uuid) resolve(["paymentIntent": paymentIntent]) } self.collectPaymentMethodCancelable = nil @@ -534,8 +523,9 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = error as NSError? { resolve(Errors.createError(nsError: error)) } else if let pi = pi { - let paymentIntent = Mappers.mapFromPaymentIntent(pi) - self.paymentIntents[pi.stripeId] = pi + let uuid = UUID().uuidString + let paymentIntent = Mappers.mapFromPaymentIntent(pi, uuid: uuid) + self.paymentIntents[uuid] = pi resolve(["paymentIntent": paymentIntent]) } } @@ -578,22 +568,22 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } @objc(confirmPaymentIntent:resolver:rejecter:) - func confirmPaymentIntent(paymentIntentId: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let id = paymentIntentId else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide paymentIntentId.")) + func confirmPaymentIntent(paymentIntentJson: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { + guard let uuid = paymentIntentJson["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) return } - - guard let paymentIntent = paymentIntents[Optional(id)] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no associated paymentIntent with id \(id)")) + guard let paymentIntent = self.paymentIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No PaymentIntent was found with the sdk_uuid \(uuid). The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent.")) return } - + Terminal.shared.confirmPaymentIntent(paymentIntent) { pi, error in if let error = error as NSError? { resolve(Errors.createError(nsError: error)) } else if let pi = pi { - let paymentIntent = Mappers.mapFromPaymentIntent(pi) + let uuid = UUID().uuidString + let paymentIntent = Mappers.mapFromPaymentIntent(pi, uuid: uuid) self.paymentIntents = [:] resolve(["paymentIntent": paymentIntent]) } @@ -609,18 +599,18 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe let result = Mappers.mapFromConnectionStatus(status) sendEvent(withName: ReactNativeConstants.CHANGE_CONNECTION_STATUS.rawValue, body: ["result": result]) } - + func reader(_ reader: Reader, didStartReconnect cancelable: Cancelable) { self.cancelReaderConnectionCancellable = cancelable let reader = Mappers.mapFromReader(reader) sendEvent(withName: ReactNativeConstants.START_READER_RECONNECT.rawValue, body: ["reader": reader]) } - + func readerDidSucceedReconnect(_ reader: Reader) { let reader = Mappers.mapFromReader(reader) sendEvent(withName: ReactNativeConstants.READER_RECONNECT_SUCCEED.rawValue, body: ["reader": reader]) } - + func readerDidFailReconnect(_ reader: Reader) { let error = Errors.createError(code: ErrorCode.unexpectedSdkError, message: "Reader reconnect fail") sendEvent(withName: ReactNativeConstants.READER_RECONNECT_FAIL.rawValue, body: error) @@ -638,20 +628,21 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } @objc(cancelPaymentIntent:resolver:rejecter:) - func cancelPaymentIntent(paymentIntentId: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let id = paymentIntentId else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide paymentIntentId.")) + func cancelPaymentIntent(paymentIntentJson: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { + guard let uuid = paymentIntentJson["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The PaymentIntent is missing sdk_uuid field. This method requires you to use the PaymentIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) return } - guard let paymentIntent = paymentIntents[Optional(id)] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no associated paymentIntent with id \(id)")) + guard let paymentIntent = self.paymentIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No PaymentIntent was found with the sdk_uuid \(uuid). The PaymentIntent provided must be re-retrieved with retrievePaymentIntent or a new PaymentIntent must be created with createPaymentIntent.")) return } Terminal.shared.cancelPaymentIntent(paymentIntent) { pi, collectError in if let error = collectError as NSError? { resolve(Errors.createError(nsError: error)) } else if let pi = pi { - let paymentIntent = Mappers.mapFromPaymentIntent(pi) + let uuid = UUID().uuidString + let paymentIntent = Mappers.mapFromPaymentIntent(pi, uuid: uuid) self.paymentIntents[pi.stripeId] = nil resolve(["paymentIntent": paymentIntent]) } @@ -691,7 +682,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe let cartBuilder = CartBuilder(currency: currency!) .setTax(Int(truncating: tax!)) .setTotal(Int(truncating: total!)) - + let cartLineItems = Mappers.mapToCartLineItems(params["lineItems"] as? NSArray ?? NSArray()) cartBuilder.setLineItems(cartLineItems) @@ -702,7 +693,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe resolve(Errors.createError(nsError: error as NSError)) return } - + Terminal.shared.setReaderDisplay(cart) { error in if let error = error as NSError? { resolve(Errors.createError(nsError: error)) @@ -713,20 +704,21 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } @objc(cancelSetupIntent:resolver:rejecter:) - func cancelSetupIntent(setupIntentId: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let id = setupIntentId else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide setupIntentId.")) + func cancelSetupIntent(setupIntentJson: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { + guard let uuid = setupIntentJson["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) return } - guard let setupIntent = setupIntents[id] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no associated setupIntentId with id \(id)")) + guard let setupIntent = self.setupIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No SetupIntent was found with the sdk_uuid \(uuid). The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent.")) return } Terminal.shared.cancelSetupIntent(setupIntent) { si, collectError in if let error = collectError as NSError? { resolve(Errors.createError(nsError: error)) } else if let si = si { - let setupIntent = Mappers.mapFromSetupIntent(si) + let uuid = UUID().uuidString + let setupIntent = Mappers.mapFromSetupIntent(si,uuid: uuid) self.setupIntents[si.stripeId] = nil resolve(["setupIntent": setupIntent]) } @@ -754,8 +746,9 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = error as NSError? { resolve(Errors.createError(nsError: error)) } else if let si = si { - self.setupIntents[si.stripeId] = si - let si = Mappers.mapFromSetupIntent(si) + let uuid = UUID().uuidString + self.setupIntents[uuid] = si + let si = Mappers.mapFromSetupIntent(si,uuid: uuid) resolve(["setupIntent": si]) } } @@ -763,14 +756,17 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe @objc(collectSetupIntentPaymentMethod:resolver:rejecter:) func collectSetupIntentPaymentMethod(params: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - let setupIntentId = params["setupIntentId"] as? String + guard let setupIntentJson = params["setupIntent"] as? NSDictionary else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide setupIntent.")) + return + } - guard let id = setupIntentId else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide setupIntentId.")) + guard let uuid = setupIntentJson["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) return } - guard let setupIntent = setupIntents[id] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no created setupIntent with id \(id)")) + guard let setupIntent = self.setupIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No SetupIntent was found with the sdk_uuid \(uuid). The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent.")) return } @@ -780,7 +776,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = collectError as NSError? { resolve(Errors.createError(nsError: error)) } else if let setupIntent = si { - let setupIntent = Mappers.mapFromSetupIntent(setupIntent) + let setupIntent = Mappers.mapFromSetupIntent(setupIntent, uuid: uuid) resolve(["setupIntent": setupIntent]) } self.collectSetupIntentCancelable = nil @@ -788,13 +784,13 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } @objc(confirmSetupIntent:resolver:rejecter:) - func confirmSetupIntent(setupIntentId: String?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - guard let id = setupIntentId else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "You must provide setupIntentId.")) + func confirmSetupIntent(setupIntentJson: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { + guard let uuid = setupIntentJson["sdk_uuid"] as? String else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "The SetupIntent is missing sdk_uuid field. This method requires you to use the SetupIntent that was returned from either createPaymentIntent or retrievePaymentIntent.")) return } - guard let setupIntent = setupIntents[id] else { - resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "There is no created setupIntent with id \(id)")) + guard let setupIntent = self.setupIntents[uuid] else { + resolve(Errors.createError(code: CommonErrorType.InvalidRequiredParameter, message: "No SetupIntent was found with the sdk_uuid \(uuid). The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent.")) return } @@ -803,7 +799,8 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe if let error = collectError as NSError? { resolve(Errors.createError(nsError: error)) } else if let setupIntent = si { - let setupIntent = Mappers.mapFromSetupIntent(setupIntent) + let uuid = UUID().uuidString + let setupIntent = Mappers.mapFromSetupIntent(setupIntent, uuid: uuid) resolve(["setupIntent": setupIntent]) } } @@ -823,7 +820,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe let intAmount = UInt(truncating: amount!); let refundApplicationFee = params["refundApplicationFee"] as? NSNumber let reverseTransfer = params["reverseTransfer"] as? NSNumber - + let refundParams: RefundParameters do { refundParams = try RefundParametersBuilder(chargeId: chargeId!,amount: intAmount, currency: currency!) diff --git a/src/StripeTerminalSdk.tsx b/src/StripeTerminalSdk.tsx index 82f09751..fee2395b 100644 --- a/src/StripeTerminalSdk.tsx +++ b/src/StripeTerminalSdk.tsx @@ -27,6 +27,8 @@ import type { ConnectLocalMobileParams, ConnectReaderResultType, CollectPaymentMethodParams, + PaymentIntent, + SetupIntent, } from './types'; const { StripeTerminalReactNative } = NativeModules; @@ -81,7 +83,7 @@ export interface StripeTerminalSdkType { retrievePaymentIntent(clientSecret: string): Promise; // Confirm Payment Intent confirmPaymentIntent( - paymentIntentId: string + paymentIntentJson: PaymentIntent.Type ): Promise; // Create Setup Intent createSetupIntent( @@ -89,7 +91,7 @@ export interface StripeTerminalSdkType { ): Promise; // Cancel Payment Intent cancelPaymentIntent( - paymentIntentId: string + paymentIntent: PaymentIntent.Type ): Promise; // Collect Setup Intent payment method collectSetupIntentPaymentMethod( @@ -107,11 +109,15 @@ export interface StripeTerminalSdkType { clearReaderDisplay(): Promise; retrieveSetupIntent(clientSecret: string): Promise; // Cancel Setup Intent - cancelSetupIntent(paymentIntentId: string): Promise; + cancelSetupIntent( + setupIntent: SetupIntent.Type + ): Promise; // List of locations belonging to the merchant getLocations(params: GetLocationsParams): Promise; // Confirm Setup Intent - confirmSetupIntent(paymentIntentId: string): Promise; + confirmSetupIntent( + setupIntent: SetupIntent.Type + ): Promise; simulateReaderUpdate(update: Reader.SimulateUpdateType): Promise; collectRefundPaymentMethod( params: RefundParams @@ -129,9 +135,6 @@ export interface StripeTerminalSdkType { cancelCollectSetupIntent(): Promise<{ error?: StripeError; }>; - cancelReadReusableCard(): Promise<{ - error?: StripeError; - }>; setSimulatedCard(cardNumber: string): Promise<{ error?: StripeError; }>; diff --git a/src/__tests__/__snapshots__/functions.test.ts.snap b/src/__tests__/__snapshots__/functions.test.ts.snap index a329e128..782697b3 100644 --- a/src/__tests__/__snapshots__/functions.test.ts.snap +++ b/src/__tests__/__snapshots__/functions.test.ts.snap @@ -8,7 +8,6 @@ Object { "cancelDiscovering": [Function], "cancelInstallingUpdate": [Function], "cancelPaymentIntent": [Function], - "cancelReadReusableCard": [Function], "cancelSetupIntent": [Function], "clearCachedCredentials": [Function], "clearReaderDisplay": [Function], diff --git a/src/__tests__/functions.test.ts b/src/__tests__/functions.test.ts index 7ad826d2..daf9ee76 100644 --- a/src/__tests__/functions.test.ts +++ b/src/__tests__/functions.test.ts @@ -125,7 +125,6 @@ describe('functions.test.ts', () => { .fn() .mockImplementation(() => ({})), cancelCollectSetupIntent: jest.fn().mockImplementation(() => ({})), - cancelReadReusableCard: jest.fn().mockImplementation(() => ({})), setSimulatedCard: jest.fn(), })); }); @@ -355,11 +354,6 @@ describe('functions.test.ts', () => { await expect(functions.cancelCollectSetupIntent()).resolves.toEqual({}); }); - it('cancelReadReusableCard returns a proper value', async () => { - const functions = require('../functions'); - await expect(functions.cancelReadReusableCard()).resolves.toEqual({}); - }); - it('connectLocalMobileReader returns a proper value', async () => { const functions = require('../functions'); await expect( diff --git a/src/functions.ts b/src/functions.ts index 1e109741..7a5132bf 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -28,6 +28,8 @@ import type { ConnectReaderResultType, ConnectHandoffParams, CollectPaymentMethodParams, + PaymentIntent, + SetupIntent, } from './types'; export async function initialize( @@ -386,12 +388,12 @@ export async function getLocations( } export async function confirmPaymentIntent( - paymentIntentId: string + paymentIntent: PaymentIntent.Type ): Promise { - return Logger.traceSdkMethod(async (innerPaymentIntentId) => { + return Logger.traceSdkMethod(async (innerPaymentIntent) => { try { - const { error, paymentIntent } = - await StripeTerminalSdk.confirmPaymentIntent(innerPaymentIntentId); + const { error, paymentIntent: confirmedPaymentIntent } = + await StripeTerminalSdk.confirmPaymentIntent(innerPaymentIntent); if (error) { return { @@ -400,7 +402,7 @@ export async function confirmPaymentIntent( }; } return { - paymentIntent: paymentIntent!, + paymentIntent: confirmedPaymentIntent!, error: undefined, }; } catch (error) { @@ -408,16 +410,16 @@ export async function confirmPaymentIntent( error: error as any, }; } - }, 'confirmPaymentIntent')(paymentIntentId); + }, 'confirmPaymentIntent')(paymentIntent); } export async function cancelPaymentIntent( - paymentIntentId: string + paymentIntent: PaymentIntent.Type ): Promise { - return Logger.traceSdkMethod(async (innerPaymentIntentId) => { + return Logger.traceSdkMethod(async (innerPaymentIntent) => { try { - const { paymentIntent, error } = - await StripeTerminalSdk.cancelPaymentIntent(innerPaymentIntentId); + const { paymentIntent: canceledPaymentIntent, error } = + await StripeTerminalSdk.cancelPaymentIntent(innerPaymentIntent); if (error) { return { @@ -426,7 +428,7 @@ export async function cancelPaymentIntent( }; } return { - paymentIntent: paymentIntent!, + paymentIntent: canceledPaymentIntent!, error: undefined, }; } catch (error) { @@ -434,7 +436,7 @@ export async function cancelPaymentIntent( error: error as any, }; } - }, 'cancelPaymentIntent')(paymentIntentId); + }, 'cancelPaymentIntent')(paymentIntent); } export async function installAvailableUpdate(): Promise<{ @@ -555,13 +557,12 @@ export async function clearReaderDisplay(): Promise { - return Logger.traceSdkMethod(async (innerSetupIntentId) => { + return Logger.traceSdkMethod(async (innerSetupIntent) => { try { - const { setupIntent, error } = await StripeTerminalSdk.cancelSetupIntent( - innerSetupIntentId - ); + const { setupIntent: canceledSetupIntent, error } = + await StripeTerminalSdk.cancelSetupIntent(innerSetupIntent); if (error) { return { @@ -570,7 +571,7 @@ export async function cancelSetupIntent( }; } return { - setupIntent: setupIntent!, + setupIntent: canceledSetupIntent!, error: undefined, }; } catch (error) { @@ -578,17 +579,16 @@ export async function cancelSetupIntent( error: error as any, }; } - }, 'cancelSetupIntent')(setupIntentId); + }, 'cancelSetupIntent')(setupIntent); } export async function confirmSetupIntent( - setupIntentId: string + setupIntent: SetupIntent.Type ): Promise { - return Logger.traceSdkMethod(async (innerSetupIntentId) => { + return Logger.traceSdkMethod(async (innerSetupIntent) => { try { - const { setupIntent, error } = await StripeTerminalSdk.confirmSetupIntent( - innerSetupIntentId - ); + const { setupIntent: confirmedSetupIntent, error } = + await StripeTerminalSdk.confirmSetupIntent(innerSetupIntent); if (error) { return { @@ -597,7 +597,7 @@ export async function confirmSetupIntent( }; } return { - setupIntent: setupIntent!, + setupIntent: confirmedSetupIntent!, error: undefined, }; } catch (error) { @@ -605,7 +605,7 @@ export async function confirmSetupIntent( error: error as any, }; } - }, 'confirmSetupIntent')(setupIntentId); + }, 'confirmSetupIntent')(setupIntent); } export async function simulateReaderUpdate( @@ -740,18 +740,3 @@ export async function cancelCollectSetupIntent(): Promise<{ } }, 'cancelCollectSetupIntent')(); } - -export async function cancelReadReusableCard(): Promise<{ - error?: StripeError; -}> { - return Logger.traceSdkMethod(async () => { - try { - await StripeTerminalSdk.cancelReadReusableCard(); - return {}; - } catch (error) { - return { - error: error as any, - }; - } - }, 'cancelReadReusableCard')(); -} diff --git a/src/hooks/__tests__/__snapshots__/useStripeTerminal.test.tsx.snap b/src/hooks/__tests__/__snapshots__/useStripeTerminal.test.tsx.snap index 0a7a04ee..c2a09668 100644 --- a/src/hooks/__tests__/__snapshots__/useStripeTerminal.test.tsx.snap +++ b/src/hooks/__tests__/__snapshots__/useStripeTerminal.test.tsx.snap @@ -9,7 +9,6 @@ Object { "cancelDiscovering": [Function], "cancelInstallingUpdate": [Function], "cancelPaymentIntent": [Function], - "cancelReadReusableCard": [Function], "cancelSetupIntent": [Function], "clearCachedCredentials": [Function], "clearReaderDisplay": [Function], diff --git a/src/hooks/__tests__/useStripeTerminal.test.tsx b/src/hooks/__tests__/useStripeTerminal.test.tsx index e89a46b2..f84e48e3 100644 --- a/src/hooks/__tests__/useStripeTerminal.test.tsx +++ b/src/hooks/__tests__/useStripeTerminal.test.tsx @@ -304,14 +304,14 @@ describe('useStripeTerminal.test.tsx', () => { result.current.cancelDiscovering(); result.current.cancelCollectRefundPaymentMethod(); result.current.cancelInstallingUpdate(); - result.current.cancelPaymentIntent(''); - result.current.cancelSetupIntent(''); + result.current.cancelPaymentIntent({} as any); + result.current.cancelSetupIntent({} as any); result.current.clearCachedCredentials(); result.current.clearReaderDisplay(); result.current.collectPaymentMethod({} as any); result.current.collectRefundPaymentMethod({} as any); result.current.collectSetupIntentPaymentMethod({} as any); - result.current.confirmSetupIntent(''); + result.current.confirmSetupIntent({} as any); result.current.connectBluetoothReader({} as any); result.current.connectHandoffReader({} as any); result.current.connectInternetReader({} as any); @@ -322,7 +322,7 @@ describe('useStripeTerminal.test.tsx', () => { result.current.disconnectReader(); result.current.retrievePaymentIntent(''); result.current.getLocations({} as any); - result.current.confirmPaymentIntent(''); + result.current.confirmPaymentIntent({} as any); result.current.retrieveSetupIntent(''); result.current.simulateReaderUpdate({} as any); result.current.setSimulatedCard(''); @@ -353,13 +353,13 @@ describe('useStripeTerminal.test.tsx', () => { result.current.cancelDiscovering(); result.current.cancelCollectRefundPaymentMethod(); result.current.cancelInstallingUpdate(); - result.current.cancelPaymentIntent(''); - result.current.cancelSetupIntent(''); + result.current.cancelPaymentIntent({} as any); + result.current.cancelSetupIntent({} as any); result.current.clearReaderDisplay(); result.current.collectPaymentMethod({} as any); result.current.collectRefundPaymentMethod({} as any); result.current.collectSetupIntentPaymentMethod({} as any); - result.current.confirmSetupIntent(''); + result.current.confirmSetupIntent({} as any); result.current.connectBluetoothReader({} as any); result.current.connectHandoffReader({} as any); result.current.connectInternetReader({} as any); @@ -370,7 +370,7 @@ describe('useStripeTerminal.test.tsx', () => { result.current.disconnectReader(); result.current.retrievePaymentIntent(''); result.current.getLocations({} as any); - result.current.confirmPaymentIntent(''); + result.current.confirmPaymentIntent({} as any); result.current.retrieveSetupIntent(''); result.current.simulateReaderUpdate({} as any); result.current.setSimulatedCard(''); diff --git a/src/hooks/useStripeTerminal.tsx b/src/hooks/useStripeTerminal.tsx index f7c1189a..89d121a2 100644 --- a/src/hooks/useStripeTerminal.tsx +++ b/src/hooks/useStripeTerminal.tsx @@ -18,6 +18,8 @@ import type { PaymentStatus, UserCallbacks, EventResult, + PaymentIntent, + SetupIntent, } from '../types'; import { discoverReaders, @@ -47,7 +49,6 @@ import { clearCachedCredentials, cancelCollectPaymentMethod, cancelCollectSetupIntent, - cancelReadReusableCard, connectHandoffReader, connectLocalMobileReader, setSimulatedCard, @@ -503,14 +504,14 @@ export function useStripeTerminal(props?: Props) { ); const _confirmPaymentIntent = useCallback( - async (paymentIntentId: string) => { + async (paymentIntent: PaymentIntent.Type) => { if (!_isInitialized()) { console.error(NOT_INITIALIZED_ERROR_MESSAGE); throw Error(NOT_INITIALIZED_ERROR_MESSAGE); } setLoading(true); - const response = await confirmPaymentIntent(paymentIntentId); + const response = await confirmPaymentIntent(paymentIntent); setLoading(false); @@ -537,14 +538,14 @@ export function useStripeTerminal(props?: Props) { ); const _cancelPaymentIntent = useCallback( - async (paymentIntentId: string) => { + async (paymentIntent: PaymentIntent.Type) => { if (!_isInitialized()) { console.error(NOT_INITIALIZED_ERROR_MESSAGE); throw Error(NOT_INITIALIZED_ERROR_MESSAGE); } setLoading(true); - const response = await cancelPaymentIntent(paymentIntentId); + const response = await cancelPaymentIntent(paymentIntent); setLoading(false); @@ -644,14 +645,14 @@ export function useStripeTerminal(props?: Props) { }, [setLoading, _isInitialized]); const _cancelSetupIntent = useCallback( - async (setupIntentId: string) => { + async (setupIntent: SetupIntent.Type) => { if (!_isInitialized()) { console.error(NOT_INITIALIZED_ERROR_MESSAGE); throw Error(NOT_INITIALIZED_ERROR_MESSAGE); } setLoading(true); - const response = await cancelSetupIntent(setupIntentId); + const response = await cancelSetupIntent(setupIntent); setLoading(false); @@ -661,14 +662,14 @@ export function useStripeTerminal(props?: Props) { ); const _confirmSetupIntent = useCallback( - async (setupIntentId: string) => { + async (setupIntent: SetupIntent.Type) => { if (!_isInitialized()) { console.error(NOT_INITIALIZED_ERROR_MESSAGE); throw Error(NOT_INITIALIZED_ERROR_MESSAGE); } setLoading(true); - const response = await confirmSetupIntent(setupIntentId); + const response = await confirmSetupIntent(setupIntent); setLoading(false); @@ -792,20 +793,6 @@ export function useStripeTerminal(props?: Props) { return response; }, [_isInitialized, setLoading]); - const _cancelReadReusableCard = useCallback(async () => { - if (!_isInitialized()) { - console.error(NOT_INITIALIZED_ERROR_MESSAGE); - throw Error(NOT_INITIALIZED_ERROR_MESSAGE); - } - setLoading(true); - - const response = await cancelReadReusableCard(); - - setLoading(false); - - return response; - }, [_isInitialized, setLoading]); - return { initialize: _initialize, discoverReaders: _discoverReaders, @@ -836,7 +823,6 @@ export function useStripeTerminal(props?: Props) { cancelCollectPaymentMethod: _cancelCollectPaymentMethod, cancelCollectRefundPaymentMethod: _cancelCollectRefundPaymentMethod, cancelCollectSetupIntent: _cancelCollectSetupIntent, - cancelReadReusableCard: _cancelReadReusableCard, connectHandoffReader: _connectHandoffReader, connectLocalMobileReader: _connectLocalMobileReader, setSimulatedCard: _setSimulatedCard, diff --git a/src/types/PaymentIntent.ts b/src/types/PaymentIntent.ts index df9859a5..caea5de9 100644 --- a/src/types/PaymentIntent.ts +++ b/src/types/PaymentIntent.ts @@ -8,6 +8,7 @@ export namespace PaymentIntent { created: string; currency: string; status: Status; + sdk_uuid: string; } export type Status = diff --git a/src/types/SetupIntent.ts b/src/types/SetupIntent.ts index 23847ca2..0e6ff461 100644 --- a/src/types/SetupIntent.ts +++ b/src/types/SetupIntent.ts @@ -8,6 +8,7 @@ export namespace SetupIntent { status: Status; latestAttempt: SetupAttempt; usage: Usage; + sdk_uuid: string; }; export type Status = diff --git a/src/types/index.ts b/src/types/index.ts index 505e720f..ed503827 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -179,7 +179,7 @@ export type PaymentMethodOptions = { }; export type CollectPaymentMethodParams = { - paymentIntentId: string; + paymentIntent: PaymentIntent.Type; skipTipping?: boolean; tipEligibleAmount?: number; updatePaymentIntent?: boolean; @@ -187,7 +187,7 @@ export type CollectPaymentMethodParams = { export type CollectSetupIntentPaymentMethodParams = { customerConsentCollected?: boolean; - setupIntentId: string; + setupIntent: SetupIntent.Type; }; export type CreateSetupIntentParams = {