diff --git a/README.md b/README.md index 3b876c3e..a654a807 100644 --- a/README.md +++ b/README.md @@ -364,17 +364,13 @@ function App() { Stripe Terminal SDK provides dedicated hook which exposes bunch of methods and props to be used within your App. Additionally, you have access to the internal state of SDK that contains information about the current connection, discovered readers and loading state. -Alternatively, you can import all of the functions directly from the module but keep in mind that you will lose the access to SDK state. - ```tsx // Screen.ts import { useStripeTerminal } from '@stripe/stripe-terminal-react-native'; -// Alternatively you can import the methods directly. import { useStripeTerminal, - discoverReaders, } from '@stripe/stripe-terminal-react-native'; export default function PaymentScreen() { diff --git a/example/src/App.tsx b/example/src/App.tsx index 93bbfe54..b53a9e43 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -99,9 +99,14 @@ export default function App() { const { initialize: initStripe } = useStripeTerminal(); const handlePermissionsSuccess = useCallback(async () => { - const { error } = await initStripe(); + const { error, reader } = await initStripe(); if (error) { Alert.alert('StripeTerminal init failed', error.message); + } else if (reader) { + console.log( + 'StripeTerminal has been initialized properly and connected to the reader', + reader + ); } else { console.log('StripeTerminal has been initialized properly'); } diff --git a/src/hooks/useStripeTerminal.tsx b/src/hooks/useStripeTerminal.tsx index b998259c..27e26d20 100644 --- a/src/hooks/useStripeTerminal.tsx +++ b/src/hooks/useStripeTerminal.tsx @@ -57,6 +57,9 @@ import { NativeModules } from 'react-native'; const { FETCH_TOKEN_PROVIDER } = NativeModules.StripeTerminalReactNative.getConstants(); +const NOT_INITIALIZED_ERROR_MESSAGE = + 'First initialize the Stripe Terminal SDK before performing any action'; + /** * useStripeTerminal hook Props */ @@ -93,6 +96,8 @@ export function useStripeTerminal(props?: Props) { setUserCallbacks, } = useContext(StripeTerminalContext); + const _isInitialized = useCallback(() => isInitialized, [isInitialized]); + const { onUpdateDiscoveredReaders, onFinishDiscoveringReaders, @@ -123,13 +128,17 @@ export function useStripeTerminal(props?: Props) { const _discoverReaders = useCallback( async (params: DiscoverReadersParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await discoverReaders(params); setLoading(false); return response; }, - [setLoading] + [_isInitialized, setLoading] ); // TODO: check why NativeEventListeners are not registering properly if there is no below fix @@ -140,19 +149,25 @@ export function useStripeTerminal(props?: Props) { const errorMessage = 'StripeTerminalProvider component is not found, has not been mounted properly or SDK has not been initialized properly'; log('Failed', errorMessage); + return { error: { code: 'Failed', message: errorMessage, }, + reader: undefined, }; } - const res = initialize(); + const res = await initialize(); return res; }, [initialize, log]); const _cancelDiscovering = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelDiscovering(); @@ -162,10 +177,14 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading, setDiscoveredReaders]); + }, [setLoading, setDiscoveredReaders, _isInitialized]); const _connectBluetoothReader = useCallback( async (params: ConnectBluetoothReaderParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await connectBluetoothReader(params); @@ -177,11 +196,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setConnectedReader, setLoading] + [setConnectedReader, setLoading, _isInitialized] ); const _connectInternetReader = useCallback( async (params: ConnectInternetReaderParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await connectInternetReader(params); @@ -193,11 +216,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setConnectedReader, setLoading] + [setConnectedReader, setLoading, _isInitialized] ); const _connectUsbReader = useCallback( async (params: ConnectUsbReaderParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await connectUsbReader(params); @@ -209,7 +236,7 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setConnectedReader, setLoading] + [_isInitialized, setConnectedReader, setLoading] ); const _connectEmbeddedReader = useCallback( @@ -261,6 +288,10 @@ export function useStripeTerminal(props?: Props) { ); const _disconnectReader = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + return; + } setLoading(true); const response = await disconnectReader(); @@ -273,10 +304,14 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading, setConnectedReader, setDiscoveredReaders]); + }, [setLoading, setConnectedReader, setDiscoveredReaders, _isInitialized]); const _createPaymentIntent = useCallback( async (params: CreatePaymentIntentParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await createPaymentIntent(params); @@ -285,11 +320,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _collectPaymentMethod = useCallback( async (paymentIntentId: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await collectPaymentMethod(paymentIntentId); @@ -298,11 +337,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _retrievePaymentIntent = useCallback( async (clientSecret: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await retrievePaymentIntent(clientSecret); @@ -311,11 +354,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _getLocations = useCallback( async (params: GetLocationsParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await getLocations(params); @@ -324,11 +371,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _processPayment = useCallback( async (paymentIntentId: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await processPayment(paymentIntentId); @@ -337,11 +388,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _createSetupIntent = useCallback( async (params: CreateSetupIntentParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await createSetupIntent(params); @@ -350,11 +405,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [_isInitialized, setLoading] ); const _cancelPaymentIntent = useCallback( async (paymentIntentId: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelPaymentIntent(paymentIntentId); @@ -363,10 +422,14 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _installAvailableUpdate = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await installAvailableUpdate(); @@ -374,19 +437,27 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _cancelInstallingUpdate = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelInstallingUpdate(); setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _setReaderDisplay = useCallback( async (cart: Cart) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await setReaderDisplay(cart); @@ -394,11 +465,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _retrieveSetupIntent = useCallback( async (clientSecret: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await retrieveSetupIntent(clientSecret); @@ -407,11 +482,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _collectSetupIntentPaymentMethod = useCallback( async (params: CollectSetupIntentPaymentMethodParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await collectSetupIntentPaymentMethod(params); @@ -419,10 +498,14 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _clearReaderDisplay = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await clearReaderDisplay(); @@ -430,10 +513,14 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _cancelSetupIntent = useCallback( async (setupIntentId: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelSetupIntent(setupIntentId); @@ -442,11 +529,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _confirmSetupIntent = useCallback( async (setupIntentId: string) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await confirmSetupIntent(setupIntentId); @@ -455,11 +546,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _simulateReaderUpdate = useCallback( async (update: Reader.SimulateUpdateType) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await simulateReaderUpdate(update); @@ -467,11 +562,15 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _collectRefundPaymentMethod = useCallback( async (params: RefundParams) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await collectRefundPaymentMethod(params); @@ -480,10 +579,14 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _processRefund = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await processRefund(); @@ -491,9 +594,13 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _clearCachedCredentials = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await clearCachedCredentials(); @@ -501,10 +608,14 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _readReusableCard = useCallback( async (params: ReadReusableCardParamsType) => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await readReusableCard(params); @@ -513,10 +624,14 @@ export function useStripeTerminal(props?: Props) { return response; }, - [setLoading] + [setLoading, _isInitialized] ); const _cancelCollectPaymentMethod = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelCollectPaymentMethod(); @@ -524,9 +639,13 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [setLoading, _isInitialized]); const _cancelCollectSetupIntent = useCallback(async () => { + if (!_isInitialized()) { + console.error(NOT_INITIALIZED_ERROR_MESSAGE); + throw Error(NOT_INITIALIZED_ERROR_MESSAGE); + } setLoading(true); const response = await cancelCollectSetupIntent(); @@ -534,9 +653,13 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [_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(); @@ -544,7 +667,7 @@ export function useStripeTerminal(props?: Props) { setLoading(false); return response; - }, [setLoading]); + }, [_isInitialized, setLoading]); return { initialize: _initialize, diff --git a/src/index.tsx b/src/index.tsx index ac06afa4..8cc8a85a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,4 @@ export * from './types'; -export * from './functions'; // hooks export {