Skip to content

Commit

Permalink
Merge pull request #11719 from Expensify/maria-refactor-verify-identi…
Browse files Browse the repository at this point in the history
…ty-for-bank-account-v2

[Refactor] VerifyIdentityForBankAccount
  • Loading branch information
stitesExpensify authored Oct 20, 2022
2 parents fb984f9 + aa460a9 commit 9a13fa3
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 45 deletions.
24 changes: 19 additions & 5 deletions src/libs/actions/BankAccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,31 @@ function connectBankAccountManually(bankAccountID, accountNumber, routingNumber,
}, getVBBADataForOnyx());
}

/**
* Verify the user's identity via Onfido
*
* @param {Number} bankAccountID
* @param {Object} onfidoData
*/
function verifyIdentityForBankAccount(bankAccountID, onfidoData) {
API.write('VerifyIdentityForBankAccount', {
bankAccountID,
onfidoData: JSON.stringify(onfidoData),
}, getVBBADataForOnyx());
}

export {
addPersonalBankAccount,
connectBankAccountManually,
deletePaymentBankAccount,
clearPersonalBankAccount,
clearPlaid,
clearOnfidoToken,
updatePersonalInformationForBankAccount,
validateBankAccount,
updateCompanyInformationForBankAccount,
updateBeneficialOwnersForBankAccount,
connectBankAccountWithPlaid,
deletePaymentBankAccount,
updateBeneficialOwnersForBankAccount,
updateCompanyInformationForBankAccount,
updatePersonalInformationForBankAccount,
updatePlaidData,
validateBankAccount,
verifyIdentityForBankAccount,
};
6 changes: 6 additions & 0 deletions src/pages/ReimbursementAccount/BankAccountStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import CONFIG from '../../CONFIG';
import ROUTES from '../../ROUTES';
import Button from '../../components/Button';
import plaidDataPropTypes from './plaidDataPropTypes';
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes';

const propTypes = {
/** Contains plaid data */
Expand All @@ -37,6 +38,10 @@ const propTypes = {
/** During the OAuth flow we need to use the plaidLink token that we initially connected with */
plaidLinkOAuthToken: PropTypes.string,

/** The bank account currently in setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccount: reimbursementAccountPropTypes,

/** Object with various information about the user */
user: PropTypes.shape({
/** Is the user account validated? */
Expand All @@ -52,6 +57,7 @@ const defaultProps = {
plaidData: {
isPlaidDisabled: false,
},
reimbursementAccount: {},
user: {},
};

Expand Down
10 changes: 10 additions & 0 deletions src/pages/ReimbursementAccount/CompanyStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@ import AddressForm from './AddressForm';
import ReimbursementAccountForm from './ReimbursementAccountForm';
import * as ReimbursementAccount from '../../libs/actions/ReimbursementAccount';
import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils';
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes';
import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes';

const propTypes = {
/** The bank account currently in setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccount: reimbursementAccountPropTypes.isRequired,

/** The draft values of the bank account being setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccountDraft: reimbursementAccountDraftPropTypes.isRequired,

...withLocalizePropTypes,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default PropTypes.shape({
requestorAddressZipCode: PropTypes.string,
dob: PropTypes.string,
ssnLast4: PropTypes.string,
isControllingOfficer: PropTypes.string,
isControllingOfficer: PropTypes.bool,
isOnfidoSetupComplete: PropTypes.bool,

/** Props needed for ACHContractStep */
Expand Down
90 changes: 90 additions & 0 deletions src/pages/ReimbursementAccount/RequestorOnfidoStep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import styles from '../../styles/styles';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import * as BankAccounts from '../../libs/actions/BankAccounts';
import Onfido from '../../components/Onfido';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils';
import Growl from '../../libs/Growl';
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes';
import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes';
import CONST from '../../CONST';

const propTypes = {
/** Bank account currently in setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccount: reimbursementAccountPropTypes.isRequired,

/** The draft values of the bank account being setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccountDraft: reimbursementAccountDraftPropTypes.isRequired,

/** The token required to initialize the Onfido SDK */
onfidoToken: PropTypes.string.isRequired,

/** A callback to call once the user completes the Onfido flow */
onComplete: PropTypes.func.isRequired,

...withLocalizePropTypes,
};

const defaultProps = {};

class RequestorOnfidoStep extends React.Component {
constructor(props) {
super(props);
this.submit = this.submit.bind(this);
}

submit(onfidoData) {
BankAccounts.verifyIdentityForBankAccount(
ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID', 0),
onfidoData,
);
this.props.onComplete();
}

render() {
return (
<ScrollView contentContainerStyle={styles.flex1}>
<Onfido
sdkToken={this.props.onfidoToken}
onUserExit={() => {
// We're taking the user back to the company step. They will need to come back to the requestor step to make the Onfido flow appear again.
BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COMPANY);
}}
onError={() => {
// In case of any unexpected error we log it to the server, show a growl, and return the user back to the company step so they can try again.
Growl.error(this.props.translate('onfidoStep.genericError'), 10000);
BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COMPANY);
}}
onSuccess={(onfidoData) => {
this.submit(onfidoData);
}}
/>
</ScrollView>
);
}
}

RequestorOnfidoStep.propTypes = propTypes;
RequestorOnfidoStep.defaultProps = defaultProps;

export default compose(
withLocalize,
withOnyx({
reimbursementAccount: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
},
onfidoToken: {
key: ONYXKEYS.ONFIDO_TOKEN,
},
reimbursementAccountDraft: {
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT,
},
}),
)(RequestorOnfidoStep);
61 changes: 22 additions & 39 deletions src/pages/ReimbursementAccount/RequestorStep.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import lodashGet from 'lodash/get';
import {ScrollView, View} from 'react-native';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import moment from 'moment';
Expand All @@ -16,19 +16,26 @@ import Text from '../../components/Text';
import * as BankAccounts from '../../libs/actions/BankAccounts';
import IdentityForm from './IdentityForm';
import * as ValidationUtils from '../../libs/ValidationUtils';
import Onfido from '../../components/Onfido';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils';
import Growl from '../../libs/Growl';
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes';
import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes';
import ReimbursementAccountForm from './ReimbursementAccountForm';
import * as Link from '../../libs/actions/Link';
import RequestorOnfidoStep from './RequestorOnfidoStep';

const propTypes = {
/** Bank account currently in setup */
/** The bank account currently in setup */
reimbursementAccount: reimbursementAccountPropTypes.isRequired,

/** The draft values of the bank account being setup */
/* eslint-disable-next-line react/no-unused-prop-types */
reimbursementAccountDraft: reimbursementAccountDraftPropTypes.isRequired,

/** The token required to initialize the Onfido SDK */
onfidoToken: PropTypes.string,

...withLocalizePropTypes,
};

Expand All @@ -42,6 +49,7 @@ class RequestorStep extends React.Component {

this.submit = this.submit.bind(this);
this.clearErrorsAndSetValues = this.clearErrorsAndSetValues.bind(this);
this.setOnfidoAsComplete = this.setOnfidoAsComplete.bind(this);

this.state = {
firstName: ReimbursementAccountUtils.getDefaultStateForField(props, 'firstName'),
Expand All @@ -53,7 +61,6 @@ class RequestorStep extends React.Component {
dob: ReimbursementAccountUtils.getDefaultStateForField(props, 'dob'),
ssnLast4: ReimbursementAccountUtils.getDefaultStateForField(props, 'ssnLast4'),
isControllingOfficer: ReimbursementAccountUtils.getDefaultStateForField(props, 'isControllingOfficer', false),
onfidoData: lodashGet(props, ['reimbursementAccount', 'achData', 'onfidoData'], ''),
isOnfidoSetupComplete: lodashGet(props, ['achData', 'isOnfidoSetupComplete'], false),
};

Expand All @@ -74,6 +81,13 @@ class RequestorStep extends React.Component {
this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props);
}

/**
* Update state to indicate that the user has completed the Onfido verification process
*/
setOnfidoAsComplete() {
this.setState({isOnfidoSetupComplete: true});
}

/**
* Clear the errors associated to keys in values if found and store the new values in the state.
*
Expand Down Expand Up @@ -147,20 +161,6 @@ class RequestorStep extends React.Component {
BankAccounts.updatePersonalInformationForBankAccount(payload);
}

submitOnfidoVerification() {
if (!this.validate()) {
return;
}

const payload = {
bankAccountID: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID', 0),
...this.state,
dob: moment(this.state.dob).format(CONST.DATE.MOMENT_FORMAT_STRING),
};

BankAccounts.setupWithdrawalAccount(payload);
}

render() {
const achData = this.props.reimbursementAccount.achData;
const shouldShowOnfido = achData.useOnfido && this.props.onfidoToken && !this.state.isOnfidoSetupComplete;
Expand All @@ -183,26 +183,9 @@ class RequestorStep extends React.Component {
onCloseButtonPress={Navigation.dismissModal}
/>
{shouldShowOnfido ? (
<ScrollView contentContainerStyle={styles.flex1}>
<Onfido
sdkToken={this.props.onfidoToken}
onUserExit={() => {
// We're taking the user back to the company step. They will need to come back to the requestor step to make the Onfido flow appear again.
BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COMPANY);
}}
onError={() => {
// In case of any unexpected error we log it to the server, show a growl, and return the user back to the company step so they can try again.
Growl.error(this.props.translate('onfidoStep.genericError'), 10000);
BankAccounts.goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COMPANY);
}}
onSuccess={(onfidoData) => {
this.setState({
onfidoData,
isOnfidoSetupComplete: true,
}, this.submitOnfidoVerification);
}}
/>
</ScrollView>
<RequestorOnfidoStep
onComplete={this.setOnfidoAsComplete}
/>
) : (
<ReimbursementAccountForm
onSubmit={this.submit}
Expand Down

0 comments on commit 9a13fa3

Please sign in to comment.