Skip to content

Commit

Permalink
Refactor VBBA setup flow
Browse files Browse the repository at this point in the history
Allow to go back from offline view
Fix and refactor startOver modal
Refactor getDefaultStateForField so people dont think reimbursementAccountDraft is not used
  • Loading branch information
nkuoch committed Dec 16, 2022
1 parent bb19a9e commit 687cac6
Show file tree
Hide file tree
Showing 31 changed files with 571 additions and 580 deletions.
1 change: 1 addition & 0 deletions config/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module.exports = (env = {}) => portfinder.getPortPromise({port: BASE_PORT})
...proxySettings,
historyApiFallback: true,
port,
https: true,
},
plugins: [
new DefinePlugin({
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ export default {
// Plaid data (access tokens, bank accounts ...)
PLAID_DATA: 'plaidData',

// If we disabled Plaid because of too many attempts
IS_PLAID_DISABLED: 'isPlaidDisabled',

// Token needed to initialize Plaid link
PLAID_LINK_TOKEN: 'plaidLinkToken',

Expand Down
21 changes: 5 additions & 16 deletions src/components/AddPlaidBankAccount.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
View,
} from 'react-native';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import Log from '../libs/Log';
import PlaidLink from './PlaidLink';
Expand All @@ -16,15 +15,15 @@ import themeColors from '../styles/themes/default';
import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import Picker from './Picker';
import plaidDataPropTypes from '../pages/ReimbursementAccount/plaidDataPropTypes';
import {plaidDataPropTypes} from '../pages/ReimbursementAccount/plaidDataPropTypes';
import Text from './Text';
import getBankIcon from './Icon/BankIcons';
import Icon from './Icon';
import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';

const propTypes = {
/** Contains plaid data */
plaidData: plaidDataPropTypes,
plaidData: plaidDataPropTypes.isRequired,

/** Selected account ID from the Picker associated with the end of the Plaid flow */
selectedPlaidAccountID: PropTypes.string,
Expand Down Expand Up @@ -57,13 +56,6 @@ const propTypes = {
};

const defaultProps = {
plaidData: {
bankName: '',
plaidAccessToken: '',
bankAccounts: [],
isLoading: false,
error: '',
},
selectedPlaidAccountID: '',
plaidLinkToken: '',
onExitPlaid: () => {},
Expand All @@ -84,7 +76,7 @@ class AddPlaidBankAccount extends React.Component {

componentDidMount() {
// If we're coming from Plaid OAuth flow then we need to reuse the existing plaidLinkToken
if ((this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) || !_.isEmpty(this.props.plaidData)) {
if ((this.props.receivedRedirectURI && this.props.plaidLinkOAuthToken) || !_.isEmpty(this.props.plaidData.bankAccounts)) {
return;
}

Expand All @@ -105,7 +97,7 @@ class AddPlaidBankAccount extends React.Component {
}

render() {
const plaidBankAccounts = lodashGet(this.props.plaidData, 'bankAccounts', []);
const plaidBankAccounts = this.props.plaidData.bankAccounts || [];
const token = this.getPlaidLinkToken();
const options = _.map(plaidBankAccounts, account => ({
value: account.plaidAccountID,
Expand All @@ -117,7 +109,7 @@ class AddPlaidBankAccount extends React.Component {
if (!plaidBankAccounts.length) {
return (
<FullPageOfflineBlockingView>
{(!token || this.props.plaidData.isLoading)
{this.props.plaidData.isLoading
&& (
<View style={[styles.flex1, styles.alignItemsCenter, styles.justifyContentCenter]}>
<ActivityIndicator color={themeColors.spinner} size="large" />
Expand Down Expand Up @@ -187,9 +179,6 @@ AddPlaidBankAccount.defaultProps = defaultProps;
export default compose(
withLocalize,
withOnyx({
plaidData: {
key: ONYXKEYS.PLAID_DATA,
},
plaidLinkToken: {
key: ONYXKEYS.PLAID_LINK_TOKEN,
initWithStoredValues: false,
Expand Down
12 changes: 10 additions & 2 deletions src/components/ReimbursementAccountLoadingIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import Navigation from '../libs/Navigation/Navigation';
import ScreenWrapper from './ScreenWrapper';
import FullScreenLoadingIndicator from './FullscreenLoadingIndicator';
import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';
import compose from '../libs/compose';
import {withNetwork} from './OnyxProvider';

const propTypes = {
/** Whether the user is submitting verifications data */
isSubmittingVerificationsData: PropTypes.bool.isRequired,

onBackButtonPress: PropTypes.func.isRequired,
...withLocalizePropTypes,
};

Expand All @@ -23,6 +25,8 @@ const ReimbursementAccountLoadingIndicator = props => (
<HeaderWithCloseButton
title={props.translate('reimbursementAccountLoadingAnimation.oneMoment')}
onCloseButtonPress={Navigation.dismissModal}
shouldShowBackButton={props.network.isOffline}
onBackButtonPress={props.onBackButtonPress}
/>
<FullPageOfflineBlockingView>
{props.isSubmittingVerificationsData ? (
Expand All @@ -49,4 +53,8 @@ const ReimbursementAccountLoadingIndicator = props => (
ReimbursementAccountLoadingIndicator.propTypes = propTypes;
ReimbursementAccountLoadingIndicator.displayName = 'ReimbursementAccountLoadingIndicator';

export default withLocalize(ReimbursementAccountLoadingIndicator);
export default compose(
withLocalize,
withNetwork(),
)(ReimbursementAccountLoadingIndicator);

24 changes: 5 additions & 19 deletions src/libs/ReimbursementAccountUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import _ from 'underscore';
import lodashGet from 'lodash/get';
import * as BankAccounts from './actions/BankAccounts';
import FormHelper from './FormHelper';
Expand All @@ -15,28 +14,16 @@ const clearErrors = (props, paths) => formHelper.clearErrors(props, paths);
/**
* Get the default state for input fields in the VBA flow
*
* @param {Object} props
* @param {Object} reimbursementAccountDraft
* @param {Object} reimbursementAccount
* @param {String} fieldName
* @param {*} defaultValue
*
* @returns {*}
*/
function getDefaultStateForField(props, fieldName, defaultValue = '') {
return lodashGet(props, ['reimbursementAccountDraft', fieldName])
|| lodashGet(props, ['reimbursementAccount', 'achData', fieldName], defaultValue);
}

/**
* @param {Object} props
* @param {Array} fieldNames
*
* @returns {*}
*/
function getBankAccountFields(props, fieldNames) {
return {
..._.pick(lodashGet(props, 'reimbursementAccount.achData'), ...fieldNames),
..._.pick(props.reimbursementAccountDraft, ...fieldNames),
};
function getDefaultStateForField(reimbursementAccountDraft, reimbursementAccount, fieldName, defaultValue = '') {
return lodashGet(reimbursementAccountDraft, fieldName)
|| lodashGet(reimbursementAccount, ['achData', fieldName], defaultValue);
}

/**
Expand All @@ -56,5 +43,4 @@ export {
clearError,
clearErrors,
getErrorText,
getBankAccountFields,
};
12 changes: 7 additions & 5 deletions src/libs/actions/BankAccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as API from '../API';
import ONYXKEYS from '../../ONYXKEYS';
import * as Localize from '../Localize';
import DateUtils from '../DateUtils';
import * as PlaidDataProps from '../../pages/ReimbursementAccount/plaidDataPropTypes';

export {
goToWithdrawalAccountSetupStep,
Expand All @@ -28,15 +29,16 @@ export {
acceptWalletTerms,
} from './Wallet';

function clearPersonalBankAccount() {
Onyx.set(ONYXKEYS.PERSONAL_BANK_ACCOUNT, {});
}

function clearPlaid() {
Onyx.set(ONYXKEYS.PLAID_DATA, {});
Onyx.set(ONYXKEYS.PLAID_DATA, PlaidDataProps.plaidDataDefaultProps);
Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, '');
}

function clearPersonalBankAccount() {
clearPlaid();
Onyx.set(ONYXKEYS.PERSONAL_BANK_ACCOUNT, {});
}

function updatePlaidData(plaidData) {
Onyx.merge(ONYXKEYS.PLAID_DATA, plaidData);
}
Expand Down
16 changes: 0 additions & 16 deletions src/libs/actions/PaymentMethods.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import _ from 'underscore';
import {createRef} from 'react';
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../../ONYXKEYS';
import * as API from '../API';
Expand All @@ -10,7 +9,6 @@ import * as Localize from '../Localize';
import Navigation from '../Navigation/Navigation';
import * as CardUtils from '../CardUtils';
import * as User from './User';
import * as store from './ReimbursementAccount/store';
import ROUTES from '../../ROUTES';

function deletePayPalMe() {
Expand All @@ -37,19 +35,6 @@ function continueSetup() {
kycWallRef.current.continue();
}

/**
* Clears local reimbursement account if it doesn't exist in bankAccounts
* @param {Object[]} bankAccounts
*/
function cleanLocalReimbursementData(bankAccounts) {
const bankAccountID = lodashGet(store.getReimbursementAccountInSetup(), 'bankAccountID');

// We check if the bank account list doesn't have the reimbursementAccount
if (!_.find(bankAccounts, bankAccount => bankAccount.bankAccountID === bankAccountID)) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: null, shouldShowResetModal: false});
}
}

function openPaymentsPage() {
const onyxData = {
optimisticData: [
Expand Down Expand Up @@ -359,7 +344,6 @@ export {
resetWalletTransferData,
saveWalletTransferAccountTypeAndID,
saveWalletTransferMethodType,
cleanLocalReimbursementData,
hasPaymentMethodError,
clearDeletePaymentMethodError,
clearAddPaymentMethodError,
Expand Down
12 changes: 11 additions & 1 deletion src/libs/actions/Plaid.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ function openPlaidBankLogin(allowDebit, bankAccountID) {
const params = getPlaidLinkTokenParameters();
params.allowDebit = allowDebit;
params.bankAccountID = bankAccountID;
API.read('OpenPlaidBankLogin', params);
API.read('OpenPlaidBankLogin', params, {
optimisticData: [{
onyxMethod: CONST.ONYX.METHOD.MERGE,
key: ONYXKEYS.PLAID_DATA,
value: {
isLoading: true,
error: '',
bankAccounts: null,
},
}],
});
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/libs/actions/ReimbursementAccount/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx';
import ONYXKEYS from '../../../ONYXKEYS';
import resetFreePlanBankAccount from './resetFreePlanBankAccount';
import deleteFromBankAccountList from './deleteFromBankAccountList';
import * as PlaidDataProps from '../../../pages/ReimbursementAccount/plaidDataPropTypes';

export {goToWithdrawalAccountSetupStep, navigateToBankAccountRoute} from './navigation';
export {
Expand All @@ -18,6 +19,11 @@ export {
*/
function setBankAccountSubStep(subStep) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {subStep}});
if (subStep === null) {
Onyx.set(ONYXKEYS.PLAID_DATA, PlaidDataProps.plaidDataDefaultProps);
Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, '');
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, {plaidAccountID: null});
}
}

function hideBankAccountErrors() {
Expand Down
86 changes: 4 additions & 82 deletions src/libs/actions/ReimbursementAccount/navigation.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,19 @@
import _ from 'underscore';
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
import * as store from './store';
import CONST from '../../../CONST';
import ONYXKEYS from '../../../ONYXKEYS';
import ROUTES from '../../../ROUTES';
import Navigation from '../../Navigation/Navigation';

const WITHDRAWAL_ACCOUNT_STEPS = [
{
id: CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT,
title: 'Bank Account',
},
{
id: CONST.BANK_ACCOUNT.STEP.COMPANY,
title: 'Company Information',
},
{
id: CONST.BANK_ACCOUNT.STEP.REQUESTOR,
title: 'Requestor Information',
},
{
id: CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT,
title: 'Beneficial Owners',
},
{
id: CONST.BANK_ACCOUNT.STEP.VALIDATION,
title: 'Validate',
},
{
id: CONST.BANK_ACCOUNT.STEP.ENABLE,
title: 'Enable',
},
];

/**
* Get step position in the array
* @private
* @param {String} stepID
* @return {Number}
*/
function getIndexByStepID(stepID) {
return _.findIndex(WITHDRAWAL_ACCOUNT_STEPS, step => step.id === stepID);
}

/**
* Get next step ID
* @param {String} [stepID]
* @return {String}
*/
function getNextStepID(stepID) {
const nextStepIndex = Math.min(
getIndexByStepID(stepID || store.getReimbursementAccountInSetup().currentStep) + 1,
WITHDRAWAL_ACCOUNT_STEPS.length - 1,
);
return lodashGet(WITHDRAWAL_ACCOUNT_STEPS, [nextStepIndex, 'id'], CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT);
}

/**
* @param {Object} achData
* @returns {String}
*/
function getNextStepToComplete(achData) {
if (achData.currentStep === CONST.BANK_ACCOUNT.STEP.REQUESTOR && !achData.isOnfidoSetupComplete) {
return CONST.BANK_ACCOUNT.STEP.REQUESTOR;
}

return getNextStepID(achData.currentStep);
}

/**
* Navigate to a specific step in the VBA flow
*
* @param {String} stepID
* @param {Object} achData
* @param {Object} newAchData
*/
function goToWithdrawalAccountSetupStep(stepID, achData) {
const newACHData = {...store.getReimbursementAccountInSetup()};

// If we go back to Requestor Step, reset any validation and previously answered questions from expectID.
if (!newACHData.useOnfido && stepID === CONST.BANK_ACCOUNT.STEP.REQUESTOR) {
delete newACHData.questions;
delete newACHData.answers;
}

// When going back to the BankAccountStep from the Company Step, show the manual form instead of Plaid
if (newACHData.currentStep === CONST.BANK_ACCOUNT.STEP.COMPANY && stepID === CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT) {
newACHData.subStep = CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL;
}
function goToWithdrawalAccountSetupStep(stepID, newAchData) {
const originalACHData = {...store.getReimbursementAccountInSetup()};

Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {...newACHData, ...achData, currentStep: stepID}});
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {...originalACHData, ...newAchData, currentStep: stepID}});
}

/**
Expand All @@ -101,7 +25,5 @@ function navigateToBankAccountRoute() {

export {
goToWithdrawalAccountSetupStep,
getNextStepToComplete,
getNextStepID,
navigateToBankAccountRoute,
};
Loading

0 comments on commit 687cac6

Please sign in to comment.