Skip to content

Commit

Permalink
Add cancelable for confirm action (#868)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-lin-bbpos authored Jan 10, 2025
1 parent 03fc9f9 commit 63e9cdf
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 16 deletions.
1 change: 0 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['StripeTerminalReactNative_' + name]).toInteger()
}


def terminalAndroidSdkVersion = '4.0.0'
def reactNativeSdkVersion = getVersionFromNpm()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
private var cancelReaderConnectionCancellable: Cancelable? = null
private var collectInputsCancelable: Cancelable? = null
private var collectDataCancelable: Cancelable? = null
private var confirmPaymentIntentCancelable: Cancelable? = null
private var confirmSetupIntentCancelable: Cancelable? = null
private var confirmRefundCancelable: Cancelable? = null

private var paymentIntents: HashMap<String, PaymentIntent?> = HashMap()
private var setupIntents: HashMap<String, SetupIntent?> = HashMap()
Expand Down Expand Up @@ -150,19 +153,49 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun cancelCollectPaymentMethod(promise: Promise) {
cancelOperation(promise, collectPaymentMethodCancelable, "collectPaymentMethod")
cancelOperation(promise, collectPaymentMethodCancelable, "collectPaymentMethod") {
collectPaymentMethodCancelable = null
}
}

@ReactMethod
@Suppress("unused")
fun cancelCollectSetupIntent(promise: Promise) {
cancelOperation(promise, collectSetupIntentCancelable, "collectSetupIntent")
cancelOperation(promise, collectSetupIntentCancelable, "collectSetupIntent") {
collectSetupIntentCancelable = null
}
}

@ReactMethod
@Suppress("unused")
fun cancelCollectRefundPaymentMethod(promise: Promise) {
cancelOperation(promise, collectRefundPaymentMethodCancelable, "collectRefundPaymentMethod")
cancelOperation(promise, collectRefundPaymentMethodCancelable, "collectRefundPaymentMethod") {
collectRefundPaymentMethodCancelable = null
}
}

@ReactMethod
@Suppress("unused")
fun cancelConfirmPaymentIntent(promise: Promise) {
cancelOperation(promise, confirmPaymentIntentCancelable, "confirmPaymentIntent") {
confirmPaymentIntentCancelable = null
}
}

@ReactMethod
@Suppress("unused")
fun cancelConfirmSetupIntent(promise: Promise) {
cancelOperation(promise, confirmSetupIntentCancelable, "confirmSetupIntent") {
confirmSetupIntentCancelable = null
}
}

@ReactMethod
@Suppress("unused")
fun cancelConfirmRefund(promise: Promise) {
cancelOperation(promise, confirmRefundCancelable, "confirmRefund") {
confirmRefundCancelable = null
}
}

@ReactMethod
Expand Down Expand Up @@ -345,9 +378,11 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
DiscoveryMethod.TAP_TO_PAY -> {
getBoolean(params, "autoReconnectOnUnexpectedDisconnect", true)
}

DiscoveryMethod.BLUETOOTH_SCAN, DiscoveryMethod.USB -> {
getBoolean(params, "autoReconnectOnUnexpectedDisconnect")
}

else -> {
false
}
Expand Down Expand Up @@ -393,7 +428,9 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun cancelReaderReconnection(promise: Promise) {
cancelOperation(promise, cancelReaderConnectionCancellable, "readerReconnection")
cancelOperation(promise, cancelReaderConnectionCancellable, "readerReconnection") {
cancelReaderConnectionCancellable = null
}
}

@OptIn(OfflineMode::class)
Expand Down Expand Up @@ -615,7 +652,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
}
val config = configBuilder.build()

terminal.confirmPaymentIntent(
confirmPaymentIntentCancelable = terminal.confirmPaymentIntent(
paymentIntent,
RNPaymentIntentCallback(promise, uuid) {
paymentIntents.clear()
Expand Down Expand Up @@ -722,7 +759,9 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun cancelInstallingUpdate(promise: Promise) {
cancelOperation(promise, installUpdateCancelable, "installUpdate")
cancelOperation(promise, installUpdateCancelable, "installUpdate") {
installUpdateCancelable = null
}
}

@ReactMethod
Expand Down Expand Up @@ -791,8 +830,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
val setupIntent = requireParam(setupIntents[uuid]) {
"No SetupIntent was found with the sdkUuid $uuid. The SetupIntent provided must be re-retrieved with retrieveSetupIntent or a new SetupIntent must be created with createSetupIntent."
}

terminal.confirmSetupIntent(
confirmSetupIntentCancelable = terminal.confirmSetupIntent(
setupIntent,
RNSetupIntentCallback(promise, uuid) {
setupIntents[it.id.orEmpty()] = null
Expand Down Expand Up @@ -885,7 +923,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun confirmRefund(promise: Promise) {
terminal.confirmRefund(RNRefundCallback(promise))
confirmRefundCancelable = terminal.confirmRefund(RNRefundCallback(promise))
}

@OptIn(OfflineMode::class)
Expand Down Expand Up @@ -1095,7 +1133,9 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun cancelCollectInputs(promise: Promise) {
cancelOperation(promise, collectInputsCancelable, "collectInputs")
cancelOperation(promise, collectInputsCancelable, "collectInputs") {
collectInputsCancelable = null
}
}

@ReactMethod
Expand Down
2 changes: 2 additions & 0 deletions dev-app/src/screens/CollectCardPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export default function CollectCardPaymentScreen() {
confirmPaymentIntent,
retrievePaymentIntent,
cancelCollectPaymentMethod,
cancelConfirmPaymentIntent,
setSimulatedCard,
getOfflineStatus,
} = useStripeTerminal({
Expand Down Expand Up @@ -449,6 +450,7 @@ export default function CollectCardPaymentScreen() {
events: [
{
name: 'Process',
onBack: cancelConfirmPaymentIntent,
description: 'terminal.confirmPaymentIntent',
metadata: { paymentIntentId: collectedPaymentIntent.id },
},
Expand Down
2 changes: 2 additions & 0 deletions dev-app/src/screens/RefundPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default function RefundPaymentScreen() {
collectRefundPaymentMethod,
cancelCollectRefundPaymentMethod,
confirmRefund,
cancelConfirmRefund,
setSimulatedCard,
} = useStripeTerminal({
onDidRequestReaderInput: (input) => {
Expand Down Expand Up @@ -144,6 +145,7 @@ export default function RefundPaymentScreen() {
events: [
{
name: 'Processing',
onBack: cancelConfirmRefund,
description: 'terminal.confirmRefund',
metadata: _refundMetadata,
},
Expand Down
4 changes: 3 additions & 1 deletion dev-app/src/screens/SetupIntentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function SetupIntentScreen() {
createSetupIntent,
collectSetupIntentPaymentMethod,
confirmSetupIntent,
cancelConfirmSetupIntent,
retrieveSetupIntent,
cancelCollectSetupIntent,
} = useStripeTerminal({
Expand Down Expand Up @@ -75,6 +76,7 @@ export default function SetupIntentScreen() {
events: [
{
name: 'Process',
onBack: cancelConfirmSetupIntent,
description: 'terminal.confirmSetupIntent',
metadata: { setupIntentId: si.id },
},
Expand Down Expand Up @@ -113,7 +115,7 @@ export default function SetupIntentScreen() {
});
}
},
[addLogs, confirmSetupIntent]
[addLogs, confirmSetupIntent, cancelConfirmSetupIntent]
);

const _collectSetupMethod = async (si: SetupIntent.Type) => {
Expand Down
15 changes: 15 additions & 0 deletions ios/StripeTerminalReactNative.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,21 @@ @interface RCT_EXTERN_MODULE(StripeTerminalReactNative, RCTEventEmitter)
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
cancelConfirmPaymentIntent:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
cancelConfirmSetupIntent:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
cancelConfirmRefund:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
getLoggingToken:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
Expand Down
61 changes: 57 additions & 4 deletions ios/StripeTerminalReactNative.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, MobileReade
var readReusableCardCancelable: Cancelable? = nil
var cancelReaderConnectionCancellable: Cancelable? = nil
var collectInputsCancellable: Cancelable? = nil
var confirmPaymentIntentCancelable: Cancelable? = nil
var confirmSetupIntentCancelable: Cancelable? = nil
var confirmRefundCancelable: Cancelable? = nil
var loggingToken: String? = nil

func terminal(_ terminal: Terminal, didUpdateDiscoveredReaders readers: [Reader]) {
Expand Down Expand Up @@ -132,6 +135,57 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, MobileReade
}
}

@objc(cancelConfirmPaymentIntent:rejecter:)
func cancelConfirmPaymentIntent(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
guard let cancelable = confirmPaymentIntentCancelable else {
resolve(Errors.createError(code: ErrorCode.cancelFailedAlreadyCompleted, message: "cancelConfirmPaymentIntent 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.confirmPaymentIntentCancelable = nil
}
}

@objc(cancelConfirmSetupIntent:rejecter:)
func cancelConfirmSetupIntent(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
guard let cancelable = confirmSetupIntentCancelable else {
resolve(Errors.createError(code: ErrorCode.cancelFailedAlreadyCompleted, message: "cancelConfirmSetupIntent 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.confirmSetupIntentCancelable = nil
}
}

@objc(cancelConfirmRefund:rejecter:)
func cancelConfirmRefund(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
guard let cancelable = confirmRefundCancelable else {
resolve(Errors.createError(code: ErrorCode.cancelFailedAlreadyCompleted, message: "cancelConfirmRefund 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.confirmRefundCancelable = nil
}
}

@objc(cancelCollectSetupIntent:rejecter:)
func cancelCollectSetupIntent(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
guard let cancelable = collectSetupIntentCancelable else {
Expand Down Expand Up @@ -628,7 +682,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, MobileReade
return
}

Terminal.shared.confirmPaymentIntent(paymentIntent,confirmConfig: confirmConfig) { pi, error in
self.confirmPaymentIntentCancelable = Terminal.shared.confirmPaymentIntent(paymentIntent,confirmConfig: confirmConfig) { pi, error in
if let error = error as NSError? {
var result = Errors.createError(nsError: error)
if let pi {
Expand Down Expand Up @@ -871,8 +925,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, MobileReade
return
}


Terminal.shared.confirmSetupIntent(setupIntent) { si, collectError in
self.confirmSetupIntentCancelable = Terminal.shared.confirmSetupIntent(setupIntent) { si, collectError in
if let error = collectError as NSError? {
resolve(Errors.createError(nsError: error))
} else if let setupIntent = si {
Expand Down Expand Up @@ -943,7 +996,7 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, MobileReade

@objc(confirmRefund:rejecter:)
func confirmRefund(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
Terminal.shared.confirmRefund() { rf, error in
self.confirmRefundCancelable = Terminal.shared.confirmRefund() { rf, error in
if let error = error as NSError? {
resolve(Errors.createError(nsError: error))
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/StripeTerminalSdk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ export interface StripeTerminalSdkType {
cancelCollectSetupIntent(): Promise<{
error?: StripeError;
}>;
cancelConfirmPaymentIntent(): Promise<{
error?: StripeError;
}>;
cancelConfirmSetupIntent(): Promise<{
error?: StripeError;
}>;
cancelConfirmRefund(): Promise<{
error?: StripeError;
}>;
setSimulatedCard(cardNumber: string): Promise<{
error?: StripeError;
}>;
Expand Down
3 changes: 3 additions & 0 deletions src/__tests__/__snapshots__/functions.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Object {
"cancelCollectPaymentMethod": [Function],
"cancelCollectRefundPaymentMethod": [Function],
"cancelCollectSetupIntent": [Function],
"cancelConfirmPaymentIntent": [Function],
"cancelConfirmRefund": [Function],
"cancelConfirmSetupIntent": [Function],
"cancelDiscovering": [Function],
"cancelInstallingUpdate": [Function],
"cancelPaymentIntent": [Function],
Expand Down
45 changes: 45 additions & 0 deletions src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,51 @@ export async function cancelCollectSetupIntent(): Promise<{
}, 'cancelCollectSetupIntent')();
}

export async function cancelConfirmPaymentIntent(): Promise<{
error?: StripeError;
}> {
return Logger.traceSdkMethod(async () => {
try {
await StripeTerminalSdk.cancelConfirmPaymentIntent();
return {};
} catch (error) {
return {
error: error as any,
};
}
}, 'cancelConfirmPaymentIntent')();
}

export async function cancelConfirmSetupIntent(): Promise<{
error?: StripeError;
}> {
return Logger.traceSdkMethod(async () => {
try {
await StripeTerminalSdk.cancelConfirmSetupIntent();
return {};
} catch (error) {
return {
error: error as any,
};
}
}, 'cancelConfirmSetupIntent')();
}

export async function cancelConfirmRefund(): Promise<{
error?: StripeError;
}> {
return Logger.traceSdkMethod(async () => {
try {
await StripeTerminalSdk.cancelConfirmRefund();
return {};
} catch (error) {
return {
error: error as any,
};
}
}, 'cancelConfirmRefund')();
}

export async function getOfflineStatus(): Promise<OfflineStatus> {
return Logger.traceSdkMethod(async () => {
try {
Expand Down
Loading

0 comments on commit 63e9cdf

Please sign in to comment.