Skip to content

Commit

Permalink
Merge pull request #20747 from Expensify/nat-plaidevent
Browse files Browse the repository at this point in the history
Handle Plaid events like secure does
  • Loading branch information
deetergp authored Aug 29, 2023
2 parents 0f5467d + 6121007 commit cf1d50a
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 4 deletions.
44 changes: 43 additions & 1 deletion src/components/AddPlaidBankAccount.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import Log from '../libs/Log';
import PlaidLink from './PlaidLink';
import * as App from '../libs/actions/App';
import * as BankAccounts from '../libs/actions/BankAccounts';
import ONYXKEYS from '../ONYXKEYS';
import styles from '../styles/styles';
Expand All @@ -22,6 +23,9 @@ import useLocalize from '../hooks/useLocalize';
import useNetwork from '../hooks/useNetwork';

const propTypes = {
/** If the user has been throttled from Plaid */
isPlaidDisabled: PropTypes.bool,

/** Contains plaid data */
plaidData: plaidDataPropTypes.isRequired,

Expand Down Expand Up @@ -63,9 +67,22 @@ const defaultProps = {
plaidLinkOAuthToken: '',
allowDebit: false,
bankAccountID: 0,
isPlaidDisabled: false,
};

function AddPlaidBankAccount({plaidData, selectedPlaidAccountID, plaidLinkToken, onExitPlaid, onSelect, text, receivedRedirectURI, plaidLinkOAuthToken, bankAccountID, allowDebit}) {
function AddPlaidBankAccount({
plaidData,
selectedPlaidAccountID,
plaidLinkToken,
onExitPlaid,
onSelect,
text,
receivedRedirectURI,
plaidLinkOAuthToken,
bankAccountID,
allowDebit,
isPlaidDisabled,
}) {
const subscribedKeyboardShortcuts = useRef([]);
const previousNetworkState = useRef();

Expand Down Expand Up @@ -154,6 +171,14 @@ function AddPlaidBankAccount({plaidData, selectedPlaidAccountID, plaidLinkToken,
const plaidDataErrorMessage = !_.isEmpty(plaidErrors) ? _.chain(plaidErrors).values().first().value() : '';
const bankName = lodashGet(plaidData, 'bankName');

if (isPlaidDisabled) {
return (
<View>
<Text style={[styles.formError]}>{translate('bankAccount.error.tooManyAttempts')}</Text>
</View>
);
}

// Plaid Link view
if (!plaidBankAccounts.length) {
return (
Expand All @@ -177,6 +202,20 @@ function AddPlaidBankAccount({plaidData, selectedPlaidAccountID, plaidLinkToken,
onError={(error) => {
Log.hmmm('[PlaidLink] Error: ', error.message);
}}
onEvent={(event, metadata) => {
// Handle Plaid login errors (will potentially reset plaid token and item depending on the error)
if (event === 'ERROR') {
Log.hmmm('[PlaidLink] Error: ', metadata);
if (bankAccountID && metadata.error_code) {
BankAccounts.handlePlaidError(bankAccountID, metadata.error_code, metadata.error_message, metadata.request_id);
}
}

// Limit the number of times a user can submit Plaid credentials
if (event === 'SUBMIT_CREDENTIALS') {
App.handleRestrictedEvent(event);
}
}}
// User prematurely exited the Plaid flow
// eslint-disable-next-line react/jsx-props-no-multi-spaces
onExit={onExitPlaid}
Expand Down Expand Up @@ -224,4 +263,7 @@ export default withOnyx({
key: ONYXKEYS.PLAID_LINK_TOKEN,
initWithStoredValues: false,
},
isPlaidDisabled: {
key: ONYXKEYS.IS_PLAID_DISABLED,
},
})(AddPlaidBankAccount);
1 change: 1 addition & 0 deletions src/components/PlaidLink/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function PlaidLink(props) {
},
onEvent: (event, metadata) => {
Log.info('[PlaidLink] Event: ', false, {event, metadata});
props.onEvent(event, metadata);
},
onLoad: () => setIsPlaidLoaded(true),

Expand Down
3 changes: 3 additions & 0 deletions src/components/PlaidLink/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ function PlaidLink(props) {
onSuccess: ({publicToken, metadata}) => {
props.onSuccess({publicToken, metadata});
},
onEvent: (event, metadata) => {
props.onEvent(event, metadata);
},
onExit: (exitError, metadata) => {
Log.info('[PlaidLink] Exit: ', false, {exitError, metadata});
props.onExit();
Expand Down
3 changes: 3 additions & 0 deletions src/components/PlaidLink/plaidLinkPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const plaidLinkPropTypes = {
// Callback to execute when the user leaves the Plaid widget flow without entering any information
onExit: PropTypes.func,

// Callback to execute whenever a Plaid event occurs
onEvent: PropTypes.func,

// The redirect URI with an OAuth state ID. Needed to re-initialize the PlaidLink after directing the
// user to their respective bank platform
receivedRedirectURI: PropTypes.string,
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ export default {
routingAndAccountNumberCannotBeSame: 'El número de ruta y el número de cuenta no pueden ser iguales',
companyType: 'Por favor, selecciona un tipo de compañía válido',
tooManyAttempts:
'Debido a la gran cantidad de intentos de inicio de sesión, esta opción se ha desactivado temporalmente durante 24 horas. Vuelve a intentarlo más tarde o introduce los detalles manualmente.',
'Debido a la gran cantidad de intentos de inicio de sesión, esta opción ha sido desactivada temporalmente durante 24 horas. Por favor, inténtalo de nuevo más tarde.',
address: 'Por favor, introduce una dirección válida',
dob: 'Por favor, selecciona una fecha de nacimiento válida',
age: 'Debe ser mayor de 18 años',
Expand Down
7 changes: 7 additions & 0 deletions src/libs/actions/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,12 @@ function beginDeepLinkRedirectAfterTransition(shouldAuthenticateWithCurrentAccou
waitForSignOnTransitionToFinish().then(() => beginDeepLinkRedirect(shouldAuthenticateWithCurrentAccount));
}

function handleRestrictedEvent(eventName) {
API.write('HandleRestrictedEvent', {
eventName,
});
}

export {
setLocale,
setLocaleAndNavigate,
Expand All @@ -474,6 +480,7 @@ export {
openApp,
reconnectApp,
confirmReadyToOpenApp,
handleRestrictedEvent,
beginDeepLinkRedirect,
beginDeepLinkRedirectAfterTransition,
createWorkspaceAndNavigateToIt,
Expand Down
10 changes: 10 additions & 0 deletions src/libs/actions/BankAccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ function openWorkspaceView() {
API.read('OpenWorkspaceView');
}

function handlePlaidError(bankAccountID, error, error_description, plaidRequestID) {
API.write('BankAccount_HandlePlaidError', {
bankAccountID,
error,
error_description,
plaidRequestID,
});
}

/**
* Set the reimbursement account loading so that it happens right away, instead of when the API command is processed.
*
Expand All @@ -419,6 +428,7 @@ export {
connectBankAccountManually,
connectBankAccountWithPlaid,
deletePaymentBankAccount,
handlePlaidError,
openPersonalBankAccountSetupView,
openReimbursementAccountPage,
updateBeneficialOwnersForBankAccount,
Expand Down
9 changes: 7 additions & 2 deletions src/pages/ReimbursementAccount/BankAccountStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,13 @@ function BankAccountStep(props) {
<Button
icon={Expensicons.Bank}
text={props.translate('bankAccount.connectOnlineWithPlaid')}
onPress={() => BankAccounts.openPlaidView()}
disabled={props.isPlaidDisabled || !props.user.validated}
onPress={() => {
if (props.isPlaidDisabled || !props.user.validated) {
return;
}
BankAccounts.openPlaidView();
}}
isDisabled={props.isPlaidDisabled || !props.user.validated}
style={[styles.mt4]}
iconStyles={[styles.buttonCTAIcon]}
shouldShowRightIcon
Expand Down

0 comments on commit cf1d50a

Please sign in to comment.