Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup "Connect bank account" workspace flow #5703

Merged
merged 31 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
73ff6ab
Move bank-account flow into workspace flow
marcaaron Oct 6, 2021
a7727f4
adding the basically done thing page but bank icons need a bankName a…
marcaaron Oct 6, 2021
16a458e
Create interstitial page to redirect or show continue button
marcaaron Oct 6, 2021
9e03ec0
fix subStep logic so that we remember the option selected;
marcaaron Oct 6, 2021
8519ad3
Fix bankName stuff
marcaaron Oct 6, 2021
74e4a55
add initial english translations
marcaaron Oct 6, 2021
235b3d9
clean up getPaymentMethods
marcaaron Oct 6, 2021
93e9d35
use initWithStoredValues
marcaaron Oct 6, 2021
d87cfc8
Remove add work email and replace with Concierge
marcaaron Oct 7, 2021
1038edf
Add noop onPress
marcaaron Oct 7, 2021
72fb8d7
dont show the continue setup screen if we are in an open state
marcaaron Oct 7, 2021
8db44a0
fix weird bug that silently breaks navigating to a new step
marcaaron Oct 7, 2021
cd2d639
pop the WorkspaceBankAccountPage before navigating to /bank-account
marcaaron Oct 7, 2021
10e27c7
remove unneeded link out to olddot
marcaaron Oct 7, 2021
62a5191
Navigate to correct next step
marcaaron Oct 7, 2021
183903a
add missing propTypes
marcaaron Oct 7, 2021
81dea7f
add translations
marcaaron Oct 7, 2021
ac85502
add translations and assets
marcaaron Oct 7, 2021
665da6d
Merge branch 'tgolen-workspace-settings' into marcaaron-connectBankAc…
marcaaron Oct 7, 2021
18b05d3
remove unneeded import
marcaaron Oct 7, 2021
6dce153
update copy
marcaaron Oct 7, 2021
89a326f
change icon
marcaaron Oct 7, 2021
198a064
remove assets
marcaaron Oct 7, 2021
c06423f
remove unused things
marcaaron Oct 7, 2021
87271a8
fix conflicts
marcaaron Oct 7, 2021
78da1f0
update route
marcaaron Oct 7, 2021
50ab411
move loading false so ACHContractStep does not reshow
marcaaron Oct 7, 2021
075fc07
add workaround for navigation
marcaaron Oct 7, 2021
d8a9be7
fix conflicts
marcaaron Oct 7, 2021
d68da52
remove pop
marcaaron Oct 7, 2021
a409a59
Remove extra dismissModal as it is no longer needed. Add a dismissMod…
marcaaron Oct 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/images/confetti-pop.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,7 @@ export default {

// Notifies all tabs that they should sign out and clear storage.
SHOULD_SIGN_OUT: 'shouldSignOut',

// Set when we are loading payment methods
IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods',
};
4 changes: 2 additions & 2 deletions src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default {
WORKSPACE_INVOICES: 'workspace/:policyID/invoices',
WORKSPACE_TRAVEL: 'workspace/:policyID/travel',
WORKSPACE_MEMBERS: 'workspace/:policyID/members',
WORKSPACE_BANKACCOUNT: 'workspace/:policyID/bankAccount',
WORKSPACE_BANK_ACCOUNT: 'workspace/:policyID/bank-account',
getWorkspaceInitialRoute: policyID => `workspace/${policyID}`,
getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`,
getWorkspaceSettingsRoute: policyID => `workspace/${policyID}/settings`,
Expand All @@ -97,7 +97,7 @@ export default {
getWorkspaceInvoicesRoute: policyID => `workspace/${policyID}/invoices`,
getWorkspaceTravelRoute: policyID => `workspace/${policyID}/travel`,
getWorkspaceMembersRoute: policyID => `workspace/${policyID}/members`,
getWorkspaceBankAccountRoute: policyID => `workspace/${policyID}/bankAccount`,
getWorkspaceBankAccountRoute: policyID => `workspace/${policyID}/bank-account`,
getRequestCallRoute: taskID => `request-call/${taskID}`,
REQUEST_CALL: 'request-call/:taskID',

Expand Down
5 changes: 4 additions & 1 deletion src/components/AddPlaidBankAccount.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,11 @@ class AddPlaidBankAccount extends React.Component {
}

const account = this.getAccounts()[this.state.selectedIndex];
const bankName = lodashGet(this.props.plaidBankAccounts, 'bankName');
this.props.onSubmit({
account, plaidLinkToken: this.props.plaidLinkToken,
bankName,
account,
plaidLinkToken: this.props.plaidLinkToken,
});
}

Expand Down
15 changes: 15 additions & 0 deletions src/components/bankAccountPropTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import PropTypes from 'prop-types';

export default PropTypes.shape({
/** The name of the institution (bank of america, etc */
addressName: PropTypes.string,

/** The masked bank account number */
accountNumber: PropTypes.string,

/** The bankAccountID in the bankAccounts db */
bankAccountID: PropTypes.number,

/** The bank account type */
type: PropTypes.string,
});
18 changes: 15 additions & 3 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,10 @@ export default {
routingNumber: 'Routing number',
addBankAccount: 'Add bank account',
chooseAnAccount: 'Choose an account',
logIntoYourBank: 'Log into your bank',
connectOnlineWithPlaid: 'Connect online with Plaid',
connectManually: 'Connect manually',
yourDataIsSecure: 'Your data is secure',
toGetStarted: 'To get started with the Expensify Card, you first need to add a bank account.',
toGetStarted: 'Add a bank account and issue corporate cards, reimburse expenses, collect invoice payments, and pay bills, all from one place.',
plaidBodyCopy: 'Give your employees an easier way to pay - and get paid back - for company expenses.',
checkHelpLine: 'Your routing number and account number can be found on a check for the account.',
validateAccountError: 'In order to finish setting up your bank account, you must validate your account. Please check your email to validate your account, and return here to finish up!',
Expand Down Expand Up @@ -592,7 +592,7 @@ export default {
reviewingInfo: 'Thanks! We\'re reviewing your information, and will be in touch shortly. Please check your chat with Concierge ',
forNextSteps: ' for next steps to finish setting up your bank account.',
letsChatCTA: 'Yes, let\'s chat!',
letsChatText: 'Thanks for providing your information! We have a couple more things to work out, but it\'ll be easier over chat. Ready to get started?',
letsChatText: 'Thanks for doing that! We have a couple more things to work out, but itll be easier over chat. Ready to chat?',
letsChatTitle: 'Let\'s chat!',
},
beneficialOwnersStep: {
Expand Down Expand Up @@ -718,6 +718,18 @@ export default {
genericFailureMessage: 'An error occurred updating the workspace, please try again.',
avatarUploadFailureMessage: 'An error occurred uploading the avatar, please try again.',
},
bankAccount: {
continueWithSetup: 'Continue with setup',
youreAlmostDone: 'You\'re almost done setting up your bank account, which will let you issue corporate cards, reimburse expenses, collect invoices, and pay bills all from the same bank account.',
streamlinePayments: 'Streamline payments',
oneMoreThing: 'One more thing!',
allSet: 'All set!',
accountDescriptionNoCards: 'This bank account will be used to reimburse expenses, collect invoices, and pay bills all from the same account.\n\nConcierge can help you add a work email address to enable the Expensify Card.',
accountDescriptionWithCards: 'This bank account will be used to issue corporate cards, reimburse expenses, collect invoices, and pay bills all from the same account.',
chatWithConcierge: 'Chat with Concierge',
letsFinishInChat: 'Let\'s finish in chat!',
almostDone: 'Almost done!',
},
},
requestCallPage: {
title: 'Request a call',
Expand Down
18 changes: 15 additions & 3 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,10 @@ export default {
routingNumber: 'Número de ruta',
addBankAccount: 'Agregar cuenta bancaria',
chooseAnAccount: 'Elige una cuenta',
logIntoYourBank: 'Inicia sesión en su banco',
connectOnlineWithPlaid: 'Conéctate a Plaid online',
connectManually: 'Conectar manualmente',
yourDataIsSecure: 'Tus datos están seguros',
toGetStarted: 'Para comenzar con la tarjeta Expensify, primero debe agregar una cuenta bancaria.',
toGetStarted: 'Añade una cuenta bancaria y emite tarjetas corporativas, reembolsa gastos y cobra y paga facturas, todo desde un mismo sitio.',
plaidBodyCopy: 'Ofrezca a sus empleados una forma más sencilla de pagar - y recuperar - los gastos de la empresa.',
checkHelpLine: 'Su número de ruta y número de cuenta se pueden encontrar en un cheque de la cuenta bancaria.',
validateAccountError: 'Para terminar de configurar tu cuenta bancaria, debes validar tu cuenta de Expensify. Por favor revisa tu correo electrónico para validar tu cuenta y regresa aquí para continuar.',
Expand Down Expand Up @@ -594,7 +594,7 @@ export default {
reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulte su chat con Concierge ',
forNextSteps: ' para conocer los próximos pasos para terminar de configurar su cuenta bancaria.',
letsChatCTA: '¡Sí, vamos a chatear!',
letsChatText: '¡Gracias por darnos tu información! Aún nos quedan algunas cosas por revisar, pero será mas fácil hacerlo por chat. ¿Estás listo para comenzar?',
letsChatText: '¡Gracias por hacer eso! Todavía tenemos que solucionar un par de cosas, pero será más fácil por chat. ¿Listo para charlar?',
letsChatTitle: '¡Vamos a chatear!',
},
beneficialOwnersStep: {
Expand Down Expand Up @@ -718,6 +718,18 @@ export default {
genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.',
avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.',
},
bankAccount: {
continueWithSetup: 'Continuar con la configuración',
youreAlmostDone: 'Casi has acabado de configurar tu cuenta bancaria, que te permitirá emitir tarjetas corporativas, reembolsar gastos y cobrar pagar facturas, todo desde la misma cuenta bancaria.',
streamlinePayments: 'Optimiza pagos',
oneMoreThing: '¡Una cosa más!',
allSet: '¡Todo listo!',
accountDescriptionNoCards: 'Esta cuenta bancaria se utilizará para reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta. Concierge puede ayudarte a añadir tu correo de trabajo para activar la Tarjeta Expensify.',
accountDescriptionWithCards: 'Esta cuenta bancaria se utilizará para emitir tarjetas corporativas, reembolsar gastos y cobrar y pagar facturas, todo desde la misma cuenta.',
chatWithConcierge: 'Chat con Concierge',
letsFinishInChat: '¡Acabemos en el chat!',
almostDone: '¡Casi listo!',
},
},
requestCallPage: {
title: 'Llámame por teléfono',
Expand Down
8 changes: 0 additions & 8 deletions src/libs/Navigation/AppNavigator/AuthScreens.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import {
SettingsModalStackNavigator,
EnablePaymentsStackNavigator,
AddPersonalBankAccountModalStackNavigator,
ReimbursementAccountModalStackNavigator,
WorkspaceInviteModalStackNavigator,
RequestCallModalStackNavigator,
ReportDetailsModalStackNavigator,
Expand Down Expand Up @@ -392,13 +391,6 @@ class AuthScreens extends React.Component {
component={AddPersonalBankAccountModalStackNavigator}
listeners={modalScreenListeners}
/>
<RootStack.Screen
name="ReimbursementAccount"
options={modalScreenOptions}
component={ReimbursementAccountModalStackNavigator}
listeners={modalScreenListeners}
initialParams={{stepToOpen: CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT}}
/>
<RootStack.Screen
name="WorkspaceInvite"
options={modalScreenOptions}
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import WorkspaceBillsPage from '../../../pages/workspace/bills/WorkspaceBillsPag
import WorkspaceTravelPage from '../../../pages/workspace/travel/WorkspaceTravelPage';
import WorkspaceMembersPage from '../../../pages/workspace/WorkspaceMembersPage';
import WorkspaceBankAccountPage from '../../../pages/workspace/WorkspaceBankAccountPage';
import CONST from '../../../CONST';

const defaultSubRouteOptions = {
cardStyle: styles.navigationScreenCardStyle,
Expand All @@ -63,6 +64,7 @@ function createModalStackNavigator(screens) {
key={screen.name}
name={screen.name}
component={screen.Component}
initialParams={screen.initialParams}
/>
))}
</ModalStackNavigator.Navigator>
Expand Down Expand Up @@ -214,6 +216,11 @@ const SettingsModalStackNavigator = createModalStackNavigator([
Component: WorkspaceBankAccountPage,
name: 'Workspace_BankAccount',
},
{
Component: ReimbursementAccountPage,
name: 'ReimbursementAccount',
initialParams: {stepToOpen: CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT},
},
]);

const EnablePaymentsStackNavigator = createModalStackNavigator([{
Expand Down
14 changes: 7 additions & 7 deletions src/libs/Navigation/linkingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,13 @@ export default {
Workspace_Members: {
path: ROUTES.WORKSPACE_MEMBERS,
},
WorkspaceBankAccountPage: {
path: ROUTES.WORKSPACE_BANKACCOUNT,
Workspace_BankAccount: {
path: ROUTES.WORKSPACE_BANK_ACCOUNT,
exact: true,
},
ReimbursementAccount: {
path: ROUTES.BANK_ACCOUNT,
exact: true,
},
},
},
Expand Down Expand Up @@ -169,11 +174,6 @@ export default {
EnablePayments_Root: ROUTES.ENABLE_PAYMENTS,
},
},
ReimbursementAccount: {
screens: {
ReimbursementAccount_Root: ROUTES.BANK_ACCOUNT,
},
},
WorkspaceInvite: {
screens: {
WorkspaceInvite_Root: ROUTES.WORKSPACE_INVITE,
Expand Down
42 changes: 35 additions & 7 deletions src/libs/actions/BankAccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function goToWithdrawalAccountSetupStep(stepID, achData) {
if (!newACHData.useOnfido && stepID === CONST.BANK_ACCOUNT.STEP.REQUESTOR) {
delete newACHData.questions;
delete newACHData.answers;
if (lodashHas(achData, CONST.BANK_ACCOUNT.VERIFICATIONS.EXTERNAL_API_RESPONSES)) {
if (lodashHas(newACHData, CONST.BANK_ACCOUNT.VERIFICATIONS.EXTERNAL_API_RESPONSES)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this because it was breaking on the next line and preventing the redirect logic I added. I don't think this should matter since we aren't using the questions and answers from expectID yet. Maybe @ctkochan22 can double check I'm not doing anything dumb here.

delete newACHData.verifications.externalApiResponses.requestorIdentityID;
delete newACHData.verifications.externalApiResponses.requestorIdentityKBA;
}
Expand Down Expand Up @@ -115,6 +115,7 @@ function getPlaidBankAccounts(publicToken, bank) {
...account,
accountNumber: Str.maskPAN(account.accountNumber),
})),
bankName,
});
});
}
Expand Down Expand Up @@ -336,6 +337,9 @@ function fetchUserWallet() {
* @param {String} [stepToOpen]
*/
function fetchFreePlanVerifiedBankAccount(stepToOpen) {
// Remember which account BankAccountStep subStep the user had before so we can set it later
const subStep = lodashGet(reimbursementAccountInSetup, 'subStep', '');

// We are using set here since we will rely on data from the server (not local data) to populate the VBA flow
// and determine which step to navigate to.
Onyx.set(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: true, error: ''});
Expand Down Expand Up @@ -379,16 +383,25 @@ function fetchFreePlanVerifiedBankAccount(stepToOpen) {
// If the user is already setting up a bank account we will continue the flow for them
let currentStep = reimbursementAccountInSetup.currentStep;
const achData = bankAccount ? bankAccount.toACHData() : {};
if (!stepToOpen && achData.currentStep) {
// eslint-disable-next-line no-use-before-define
currentStep = getNextStepToComplete(achData);
}

achData.useOnfido = true;
achData.policyID = reimbursementAccountWorkspaceID || '';
achData.isInSetup = !bankAccount || bankAccount.isInSetup();
achData.bankAccountInReview = bankAccount && bankAccount.isVerifying();
achData.domainLimit = 0;

// If the bank account has already been created in the db and is not yet open
// let's show the manual form with the previously added values
achData.subStep = bankAccount && bankAccount.isInSetup()
&& CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL;
// let's show the manual form with the previously added values. Otherwise, we will
// make the subStep the previous value.
if (bankAccount && bankAccount.isInSetup()) {
achData.subStep = CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL;
} else {
achData.subStep = subStep;
}

// If we're not in setup, it means we already have a withdrawal account
// and we're upgrading it to a business bank account. So let the user
Expand Down Expand Up @@ -504,16 +517,29 @@ function getIndexByStepID(stepID) {

/**
* Get next step ID
* @param {String} [stepID]
* @return {String}
*/
function getNextStepID() {
function getNextStepID(stepID) {
const nextStepIndex = Math.min(
getIndexByStepID(reimbursementAccountInSetup.currentStep) + 1,
getIndexByStepID(stepID || reimbursementAccountInSetup.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);
}

/**
* @private
* @param {Number} bankAccountID
Expand Down Expand Up @@ -651,7 +677,7 @@ function setupWithdrawalAccount(data) {

API.BankAccount_SetupWithdrawal(newACHData)
.then((response) => {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false, achData: {...newACHData}});
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {...newACHData}});
const currentStep = newACHData.currentStep;
let achData = lodashGet(response, 'achData', {});
let error = lodashGet(achData, CONST.BANK_ACCOUNT.VERIFICATIONS.ERROR_MESSAGE);
Expand Down Expand Up @@ -720,6 +746,7 @@ function setupWithdrawalAccount(data) {
|| achData.state === BankAccount.STATE.VERIFYING;

goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.VALIDATION, achData);
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false});
});
return;
}
Expand Down Expand Up @@ -763,6 +790,7 @@ function setupWithdrawalAccount(data) {
showBankAccountFormValidationError(error);
showBankAccountErrorModal(error);
}
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false});
})
.catch((response) => {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: false, achData: {...newACHData}});
Expand Down
2 changes: 2 additions & 0 deletions src/libs/actions/PaymentMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {maskCardNumber} from '../cardUtils';
* @returns {Promise}
*/
function getPaymentMethods() {
Onyx.set(ONYXKEYS.IS_LOADING_PAYMENT_METHODS, true);
return API.Get({
returnValueList: 'bankAccountList, fundList, userWallet, nameValuePairs',
name: 'paypalMeAddress',
Expand All @@ -24,6 +25,7 @@ function getPaymentMethods() {
})
.then((response) => {
Onyx.multiSet({
[ONYXKEYS.IS_LOADING_PAYMENT_METHODS]: false,
[ONYXKEYS.USER_WALLET]: lodashGet(response, 'userWallet', {}),
[ONYXKEYS.BANK_ACCOUNT_LIST]: lodashGet(response, 'bankAccountList', []),
[ONYXKEYS.CARD_LIST]: lodashGet(response, 'fundList', []),
Expand Down
Loading