From f63584fca8ac8bb9ae0a95f641c2784fa9c1c836 Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 08:40:00 -0600 Subject: [PATCH 1/7] fixing hooks deps --- example/src/App.tsx | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index 029f6518..ac3f8ad3 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -105,6 +105,17 @@ export default function App() { const { initialize: initStripe } = useStripeTerminal(); useEffect(() => { + const handlePermissionsSuccess = async () => { + const { error } = await initStripe({ + logLevel: 'verbose', + }); + if (error) { + Alert.alert('StripeTerminal init failed', error.message); + } else { + console.log('StripeTerminal has been initialized properly'); + } + }; + async function handlePermissions() { try { const granted = await PermissionsAndroid.request( @@ -157,8 +168,7 @@ export default function App() { } else { handlePermissionsSuccess(); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [initStripe]); const handlePermissionsError = () => { console.error( @@ -166,17 +176,6 @@ export default function App() { ); }; - const handlePermissionsSuccess = async () => { - const { error } = await initStripe({ - logLevel: 'verbose', - }); - if (error) { - Alert.alert('StripeTerminal init failed', error.message); - } else { - console.log('StripeTerminal has been initialized properly'); - } - }; - const hasGrantedPermission = (status: string) => { return status === PermissionsAndroid.RESULTS.GRANTED; }; From f0683afa0e7f198e9c5409688d37e353a8f3bb97 Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 09:31:56 -0600 Subject: [PATCH 2/7] fix android all target --- example/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/package.json b/example/package.json index 030221a9..c245ee45 100644 --- a/example/package.json +++ b/example/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "android": "react-native run-android", - "android:all": "concurrently \"yarn start\" \"yarn start:server\" \"yarn ios\"", + "android:all": "concurrently \"yarn start\" \"yarn start:server\" \"yarn android\"", "bootstrap": "cd .. && yarn bootstrap", "build:server": "babel server --out-dir dist --extensions '.ts,.tsx' --ignore '**/__tests__/**' --source-maps --copy-files --delete-dir-on-start", "ios": "react-native run-ios", From a91a8aa8290e6727d5d38f7217904d3d125491a9 Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 11:48:13 -0600 Subject: [PATCH 3/7] pushing looping location check --- example/src/screens/LocationListScreen.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/src/screens/LocationListScreen.tsx b/example/src/screens/LocationListScreen.tsx index 4a754445..22de29a3 100644 --- a/example/src/screens/LocationListScreen.tsx +++ b/example/src/screens/LocationListScreen.tsx @@ -22,14 +22,14 @@ export default function LocationListScreen() { useEffect(() => { async function init() { + console.log('getting locations'); const { locations } = await getLocations({ limit: 20 }); if (locations) { setList(locations); } } init(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [getLocations]); const renderItem = (item: Location) => ( Date: Tue, 29 Mar 2022 13:19:28 -0600 Subject: [PATCH 4/7] memoize context --- src/components/StripeTerminalProvider.tsx | 59 +++++++++++++---------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/components/StripeTerminalProvider.tsx b/src/components/StripeTerminalProvider.tsx index 8029024d..cb5963c0 100644 --- a/src/components/StripeTerminalProvider.tsx +++ b/src/components/StripeTerminalProvider.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useRef, useState } from 'react'; +import React, { useCallback, useRef, useState, useMemo } from 'react'; import type { Reader, InitParams, @@ -237,9 +237,9 @@ export function StripeTerminalProvider({ useListener(CHANGE_PAYMENT_STATUS, didChangePaymentStatus); useListener(CHANGE_CONNECTION_STATUS, didChangeConnectionStatus); - const setUserCallbacks = (callbacks: UserCallbacks) => { + const setUserCallbacks = useCallback((callbacks: UserCallbacks) => { userCallbacks.current = callbacks; - }; + }, []); const _initialize = useCallback( async (params: InitParams) => { @@ -265,29 +265,38 @@ export function StripeTerminalProvider({ [setLoading, setConnectedReader, setIsInitialized, log] ); + const value = useMemo( + () => ({ + loading, + isInitialized, + connectedReader, + discoveredReaders, + setIsInitialized, + setLoading, + setConnectedReader, + setDiscoveredReaders, + log, + initialize: _initialize, + setUserCallbacks, + emitter, + }), + [ + _initialize, + loading, + isInitialized, + connectedReader, + discoveredReaders, + setIsInitialized, + setLoading, + setConnectedReader, + setDiscoveredReaders, + log, + setUserCallbacks, + ] + ); + return ( - { - setLoading(value); - }, - setConnectedReader: (value) => { - setConnectedReader(value); - }, - setDiscoveredReaders: (values) => { - setDiscoveredReaders(values); - }, - log, - initialize: _initialize, - setUserCallbacks, - emitter, - }} - > + {children} ); From 2e3f63afcbcd15af8ba9b798f02fc97958b5db4c Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 13:25:14 -0600 Subject: [PATCH 5/7] discover --- example/src/screens/DiscoverReadersScreen.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/example/src/screens/DiscoverReadersScreen.tsx b/example/src/screens/DiscoverReadersScreen.tsx index 7b527802..4e4c039c 100644 --- a/example/src/screens/DiscoverReadersScreen.tsx +++ b/example/src/screens/DiscoverReadersScreen.tsx @@ -123,7 +123,7 @@ export default function DiscoverReadersScreen() { }); }, [navigation, cancelDiscovering, discoveringLoading, handleGoBack]); - const handleDiscoverReaders = async () => { + const handleDiscoverReaders = useCallback(async () => { setDiscoveringLoading(true); // List of discovered readers will be available within useStripeTerminal hook const { error: discoverReadersError } = await discoverReaders({ @@ -138,13 +138,12 @@ export default function DiscoverReadersScreen() { navigation.goBack(); } } - }; + }, [navigation, discoverReaders, discoveryMethod, simulated]); useEffect(() => { simulateReaderUpdate('none'); handleDiscoverReaders(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [handleDiscoverReaders, simulateReaderUpdate]); const handleConnectReader = async (reader: Reader.Type) => { let error: StripeError | undefined; From 78370863a8777e5407aff786b96c4b962a2e665a Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 13:46:54 -0600 Subject: [PATCH 6/7] rrc --- example/src/App.tsx | 21 +++++++++---------- .../src/screens/ReadReusableCardScreen.tsx | 15 +++++++------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index ac3f8ad3..f159b929 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useMemo, useEffect, useState } from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator, @@ -101,7 +101,7 @@ const screenOptions = { export default function App() { const [logs, setlogs] = useState([]); - const clearLogs = () => setlogs([]); + const clearLogs = useCallback(() => setlogs([]), []); const { initialize: initStripe } = useStripeTerminal(); useEffect(() => { @@ -180,7 +180,7 @@ export default function App() { return status === PermissionsAndroid.RESULTS.GRANTED; }; - const addLogs = (newLog: Log) => { + const addLogs = useCallback((newLog: Log) => { const updateLog = (log: Log) => log.name === newLog.name ? { name: log.name, events: [...log.events, ...newLog.events] } @@ -190,16 +190,15 @@ export default function App() { ? prev.map(updateLog) : [...prev, newLog] ); - }; + }, []); + + const value = useMemo( + () => ({ logs, addLogs, clearLogs }), + [logs, addLogs, clearLogs] + ); return ( - + <> { - _readReusableCard(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const _readReusableCard = async () => { + const _readReusableCard = useCallback(async () => { clearLogs(); navigation.navigate('LogListScreen'); @@ -93,7 +88,11 @@ export default function ReadReusableCardScreen() { ], }); } - }; + }, [navigation, readReusableCard, addLogs, clearLogs]); + + useEffect(() => { + _readReusableCard(); + }, [_readReusableCard]); return ; } From d081df58b99a19ff13fe00e586ebd5b8c2f16d72 Mon Sep 17 00:00:00 2001 From: Jason Divock Date: Tue, 29 Mar 2022 13:52:41 -0600 Subject: [PATCH 7/7] setupIntents --- example/src/screens/LocationListScreen.tsx | 1 - example/src/screens/SetupIntentScreen.tsx | 195 +++++++++++---------- 2 files changed, 104 insertions(+), 92 deletions(-) diff --git a/example/src/screens/LocationListScreen.tsx b/example/src/screens/LocationListScreen.tsx index 22de29a3..f1c1bdeb 100644 --- a/example/src/screens/LocationListScreen.tsx +++ b/example/src/screens/LocationListScreen.tsx @@ -22,7 +22,6 @@ export default function LocationListScreen() { useEffect(() => { async function init() { - console.log('getting locations'); const { locations } = await getLocations({ limit: 20 }); if (locations) { setList(locations); diff --git a/example/src/screens/SetupIntentScreen.tsx b/example/src/screens/SetupIntentScreen.tsx index c2037c1d..5d53e8a4 100644 --- a/example/src/screens/SetupIntentScreen.tsx +++ b/example/src/screens/SetupIntentScreen.tsx @@ -1,5 +1,5 @@ import { RouteProp, useNavigation, useRoute } from '@react-navigation/core'; -import React, { useContext, useEffect } from 'react'; +import React, { useCallback, useContext, useEffect } from 'react'; import { ScrollView, StyleSheet } from 'react-native'; import { SetupIntent, @@ -50,11 +50,6 @@ export default function SetupIntentScreen() { }, }); - useEffect(() => { - _createSetupIntent(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const createServerSetupIntent = async () => { try { const response = await fetch(`${API_URL}/create_setup_intent`, { @@ -71,7 +66,97 @@ export default function SetupIntentScreen() { } }; - const _createSetupIntent = async () => { + const _processPayment = useCallback( + async (setupIntentId: string) => { + addLogs({ + name: 'Process Payment', + events: [ + { + name: 'Process', + description: 'terminal.confirmSetupIntent', + metadata: { setupIntentId }, + }, + ], + }); + const { setupIntent, error } = await confirmSetupIntent(setupIntentId); + if (error) { + addLogs({ + name: 'Process Payment', + events: [ + { + name: 'Failed', + description: 'terminal.confirmSetupIntent', + metadata: { + errorCode: error.code, + errorMessage: error.message, + }, + }, + ], + }); + } else if (setupIntent) { + addLogs({ + name: 'Process Payment', + events: [ + { + name: 'Finished', + description: 'terminal.confirmSetupIntent', + metadata: { setupIntentId: setupIntent.id }, + }, + ], + }); + } + }, + [addLogs, confirmSetupIntent] + ); + + const _collectPaymentMethod = useCallback( + async (setupIntentId: string) => { + addLogs({ + name: 'Collect Setup Intent', + events: [ + { + name: 'Collect', + description: 'terminal.collectSetupIntentPaymentMethod', + metadata: { setupIntentId }, + }, + ], + }); + const { setupIntent, error } = await collectSetupIntentPaymentMethod({ + setupIntentId: setupIntentId, + customerConsentCollected: true, + }); + if (error) { + addLogs({ + name: 'Collect Setup Intent', + events: [ + { + name: 'Failed', + description: 'terminal.collectSetupIntentPaymentMethod', + metadata: { + errorCode: error.code, + errorMessage: error.message, + }, + }, + ], + }); + } else if (setupIntent) { + addLogs({ + name: 'Collect Setup Intent', + events: [ + { + name: 'Created', + description: 'terminal.collectSetupIntentPaymentMethod', + metadata: { setupIntentId: setupIntent.id }, + }, + ], + }); + await _processPayment(setupIntentId); + } + }, + [_processPayment, addLogs, collectSetupIntentPaymentMethod] + ); + + const _createSetupIntent = useCallback(async () => { clearLogs(); navigation.navigate('LogListScreen'); addLogs({ @@ -129,91 +214,19 @@ export default function SetupIntentScreen() { } else if (setupIntent) { await _collectPaymentMethod(setupIntent.id); } - }; - - const _collectPaymentMethod = async (setupIntentId: string) => { - addLogs({ - name: 'Collect Setup Intent', - events: [ - { - name: 'Collect', - description: 'terminal.collectSetupIntentPaymentMethod', - metadata: { setupIntentId }, - }, - ], - }); - const { setupIntent, error } = await collectSetupIntentPaymentMethod({ - setupIntentId: setupIntentId, - customerConsentCollected: true, - }); - if (error) { - addLogs({ - name: 'Collect Setup Intent', - events: [ - { - name: 'Failed', - description: 'terminal.collectSetupIntentPaymentMethod', - metadata: { - errorCode: error.code, - errorMessage: error.message, - }, - }, - ], - }); - } else if (setupIntent) { - addLogs({ - name: 'Collect Setup Intent', - events: [ - { - name: 'Created', - description: 'terminal.collectSetupIntentPaymentMethod', - metadata: { setupIntentId: setupIntent.id }, - }, - ], - }); - await _processPayment(setupIntentId); - } - }; + }, [ + _collectPaymentMethod, + createSetupIntent, + addLogs, + clearLogs, + discoveryMethod, + navigation, + retrieveSetupIntent, + ]); - const _processPayment = async (setupIntentId: string) => { - addLogs({ - name: 'Process Payment', - events: [ - { - name: 'Process', - description: 'terminal.confirmSetupIntent', - metadata: { setupIntentId }, - }, - ], - }); - const { setupIntent, error } = await confirmSetupIntent(setupIntentId); - if (error) { - addLogs({ - name: 'Process Payment', - events: [ - { - name: 'Failed', - description: 'terminal.confirmSetupIntent', - metadata: { - errorCode: error.code, - errorMessage: error.message, - }, - }, - ], - }); - } else if (setupIntent) { - addLogs({ - name: 'Process Payment', - events: [ - { - name: 'Finished', - description: 'terminal.confirmSetupIntent', - metadata: { setupIntentId: setupIntent.id }, - }, - ], - }); - } - }; + useEffect(() => { + _createSetupIntent(); + }, [_createSetupIntent]); return ; }