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

feat: BankInfo step #31121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,21 @@ const CONST = {
DOMAIN: '@expensify.sms',
},
BANK_ACCOUNT: {
BANK_INFO_STEP: {
INPUT_KEY: {
BANK_ACCOUNT_ID: 'bankAccountID',
ROUTING_NUMBER: 'routingNumber',
ACCOUNT_NUMBER: 'accountNumber',
PLAID_MASK: 'plaidMask',
IS_SAVINGS: 'isSavings',
BANK_NAME: 'bankName',
PLAID_ACCOUNT_ID: 'plaidAccountID',
PLAID_ACCESS_TOKEN: 'plaidAccessToken',
},
},
PERSONAL_INFO_STEP: {
INPUT_KEY: {
BANK_ACCOUNT_ID: 'bankAccountID',
FIRST_NAME: 'firstName',
LAST_NAME: 'lastName',
DOB: 'dob',
Expand Down Expand Up @@ -223,6 +236,7 @@ const CONST = {
},
SUBSTEP: {
MANUAL: 'manual',
PLAID: 'plaid',
},
VERIFICATIONS: {
ERROR_MESSAGE: 'verifications.errorMessage',
Expand Down
59 changes: 56 additions & 3 deletions src/components/AddPlaidBankAccount.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useRef} from 'react';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {ActivityIndicator, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
Expand All @@ -20,6 +20,7 @@ import Icon from './Icon';
import getBankIcon from './Icon/BankIcons';
import Picker from './Picker';
import PlaidLink from './PlaidLink';
import RadioButtons from './RadioButtons';
import Text from './Text';

const propTypes = {
Expand Down Expand Up @@ -55,6 +56,9 @@ const propTypes = {

/** Are we adding a withdrawal account? */
allowDebit: PropTypes.bool,

/** Is displayed in new VBBA */
isDisplayedInNewVBBA: PropTypes.bool,
};

const defaultProps = {
Expand All @@ -68,6 +72,7 @@ const defaultProps = {
allowDebit: false,
bankAccountID: 0,
isPlaidDisabled: false,
isDisplayedInNewVBBA: false,
};

function AddPlaidBankAccount({
Expand All @@ -82,11 +87,21 @@ function AddPlaidBankAccount({
bankAccountID,
allowDebit,
isPlaidDisabled,
isDisplayedInNewVBBA,
}) {
const theme = useTheme();
const styles = useThemeStyles();
const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts', []);
const defaultSelectedPlaidAccount = _.find(plaidBankAccounts, (account) => account.plaidAccountID === selectedPlaidAccountID);
const defaultSelectedPlaidAccountID = lodashGet(defaultSelectedPlaidAccount, 'plaidAccountID', '');
const defaultSelectedPlaidAccountMask = lodashGet(
_.find(plaidBankAccounts, (account) => account.plaidAccountID === selectedPlaidAccountID),
'mask',
'',
);
const subscribedKeyboardShortcuts = useRef([]);
const previousNetworkState = useRef();
const [selectedPlaidAccountMask, setSelectedPlaidAccountMask] = useState(defaultSelectedPlaidAccountMask);

const {translate} = useLocalize();
const {isOffline} = useNetwork();
Expand Down Expand Up @@ -162,17 +177,27 @@ function AddPlaidBankAccount({
previousNetworkState.current = isOffline;
}, [allowDebit, bankAccountID, isAuthenticatedWithPlaid, isOffline]);

const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts') || [];
const token = getPlaidLinkToken();
const options = _.map(plaidBankAccounts, (account) => ({
value: account.plaidAccountID,
label: `${account.addressName} ${account.mask}`,
label: account.addressName,
}));
const {icon, iconSize, iconStyles} = getBankIcon();
const plaidErrors = lodashGet(plaidData, 'errors');
const plaidDataErrorMessage = !_.isEmpty(plaidErrors) ? _.chain(plaidErrors).values().first().value() : '';
const bankName = lodashGet(plaidData, 'bankName');

/**
* @param {String} plaidAccountID
*
* When user selects one of plaid accounts we need to set the mask in order to display it on UI
*/
const handleSelectingPlaidAccount = (plaidAccountID) => {
const mask = _.find(plaidBankAccounts, (account) => account.plaidAccountID === plaidAccountID).mask;
setSelectedPlaidAccountMask(mask);
onSelect(plaidAccountID);
};

if (isPlaidDisabled) {
return (
<View>
Expand Down Expand Up @@ -229,6 +254,34 @@ function AddPlaidBankAccount({
);
}

if (isDisplayedInNewVBBA) {
return (
<FullPageOfflineBlockingView>
<Text style={[styles.mb5, styles.textHeadline]}>{translate('bankAccount.chooseAnAccount')}</Text>
{!_.isEmpty(text) && <Text style={[styles.mb5]}>{text}</Text>}
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mb5]}>
<Icon
src={icon}
height={iconSize}
width={iconSize}
/>
<View>
<Text style={[styles.ml3, styles.textStrong]}>{bankName}</Text>
{selectedPlaidAccountMask.length > 0 && (
<Text style={[styles.ml3, styles.textLabelSupporting]}>{`${translate('bankAccount.accountEnding')} ${selectedPlaidAccountMask}`}</Text>
)}
</View>
</View>
<Text style={[styles.textLabelSupporting]}>{`${translate('bankAccount.chooseAnAccountBelow')}:`}</Text>
<RadioButtons
items={options}
defaultCheckedValue={defaultSelectedPlaidAccountID}
onPress={handleSelectingPlaidAccount}
/>
</FullPageOfflineBlockingView>
);
}

// Plaid bank accounts view
return (
<FullPageOfflineBlockingView>
Expand Down
21 changes: 19 additions & 2 deletions src/components/NewDatePicker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import * as Expensicons from '@components/Icon/Expensicons';
import TextInput from '@components/TextInput';
import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '@components/TextInput/BaseTextInput/baseTextInputPropTypes';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import * as FormActions from '@userActions/FormActions';
import useThemeStyles from '@styles/useThemeStyles';
import * as FormActions from '@userActions/FormActions';
import CONST from '@src/CONST';
import CalendarPicker from './CalendarPicker';

Expand Down Expand Up @@ -53,7 +53,24 @@ const datePickerDefaultProps = {
formID: '',
};

function NewDatePicker({containerStyles, defaultValue, disabled, errorText, inputID, isSmallScreenWidth, label, maxDate, minDate, onInputChange, onTouched, placeholder, translate, value, shouldSaveDraft, formID}) {
function NewDatePicker({
containerStyles,
defaultValue,
disabled,
errorText,
inputID,
isSmallScreenWidth,
label,
maxDate,
minDate,
onInputChange,
onTouched,
placeholder,
translate,
value,
shouldSaveDraft,
formID,
}) {
const styles = useThemeStyles();
const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined);

Expand Down
7 changes: 5 additions & 2 deletions src/components/RadioButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ type RadioButtonsProps = {
/** List of choices to display via radio buttons */
items: Choice[];

/** Default checked value */
defaultCheckedValue?: string;

/** Callback to fire when selecting a radio button */
onPress: (value: string) => void;
};

function RadioButtons({items, onPress}: RadioButtonsProps) {
function RadioButtons({items, onPress, defaultCheckedValue = ''}: RadioButtonsProps) {
const styles = useThemeStyles();
const [checkedValue, setCheckedValue] = useState('');
const [checkedValue, setCheckedValue] = useState(defaultCheckedValue);

return (
<View>
Expand Down
8 changes: 8 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1140,8 +1140,16 @@ export default {
return result;
},
bankAccount: {
bankInfo: 'Bank info',
confirmBankInfo: 'Confirm bank info',
manuallyAdd: 'Manually add your bank account',
letsDoubleCheck: "Let's double check that everything looks right.",
accountEnding: 'Account ending in',
thisBankAccount: 'This bank account will be used for business payments on your workspace',
connectDifferentAccount: 'Connect a different account',
accountNumber: 'Account number',
routingNumber: 'Routing number',
chooseAnAccountBelow: 'Choose an account below',
addBankAccount: 'Add bank account',
chooseAnAccount: 'Choose an account',
connectOnlineWithPlaid: 'Connect online with Plaid',
Expand Down
8 changes: 8 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,16 @@ export default {
return result;
},
bankAccount: {
bankInfo: 'Información bancaria',
confirmBankInfo: 'Confirmar información bancaria',
manuallyAdd: 'Agregar manualmente tu cuenta bancaria',
letsDoubleCheck: 'Verifiquemos que todo esté correcto.',
accountEnding: 'Cuenta terminada en',
thisBankAccount: 'Esta cuenta bancaria se utilizará para pagos comerciales en tu espacio de trabajo',
connectDifferentAccount: 'Conectar una cuenta diferente',
accountNumber: 'Número de cuenta',
routingNumber: 'Número de ruta',
chooseAnAccountBelow: 'Elige una cuenta a continuación',
addBankAccount: 'Añadir cuenta bancaria',
chooseAnAccount: 'Elige una cuenta',
connectOnlineWithPlaid: 'Conéctate a Plaid online',
Expand Down
28 changes: 27 additions & 1 deletion src/pages/ReimbursementAccount/BankAccountStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import useTheme from '@styles/themes/useTheme';
import useThemeStyles from '@styles/useThemeStyles';
import * as BankAccounts from '@userActions/BankAccounts';
import * as Link from '@userActions/Link';
import * as ReimbursementAccount from '@userActions/ReimbursementAccount';
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import BankAccountManualStep from './BankAccountManualStep';
import BankAccountPlaidStep from './BankAccountPlaidStep';
import BankInfo from './BankInfo/BankInfo';
import StepPropTypes from './StepPropTypes';

const propTypes = {
Expand Down Expand Up @@ -63,6 +65,8 @@ const defaultProps = {
policyID: '',
};

const bankInfoStepKeys = CONST.BANK_ACCOUNT.BANK_INFO_STEP.INPUT_KEY;

function BankAccountStep(props) {
const theme = useTheme();
const styles = useThemeStyles();
Expand All @@ -78,6 +82,23 @@ function BankAccountStep(props) {
ROUTES.WORKSPACE_INITIAL.getRoute(props.policyID),
)}`;

const removeExistingBankAccountDetails = () => {
const bankAccountData = {
[bankInfoStepKeys.ROUTING_NUMBER]: '',
[bankInfoStepKeys.ACCOUNT_NUMBER]: '',
[bankInfoStepKeys.PLAID_MASK]: '',
[bankInfoStepKeys.IS_SAVINGS]: '',
[bankInfoStepKeys.BANK_NAME]: '',
[bankInfoStepKeys.PLAID_ACCOUNT_ID]: '',
[bankInfoStepKeys.PLAID_ACCESS_TOKEN]: '',
};
ReimbursementAccount.updateReimbursementAccountDraft(bankAccountData);
};

if (subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID || subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL) {
return <BankInfo />;
}

if (subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL) {
return (
<BankAccountManualStep
Expand All @@ -100,6 +121,7 @@ function BankAccountStep(props) {
);
}

// TODO Move initial screen where you select setup type to new ReimbursementAccount page as the begining of whole flow; also cleanup once this is done
return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
Expand Down Expand Up @@ -134,6 +156,7 @@ function BankAccountStep(props) {
if (props.isPlaidDisabled || !props.user.validated) {
return;
}
removeExistingBankAccountDetails();
BankAccounts.openPlaidView();
}}
isDisabled={props.isPlaidDisabled || !props.user.validated}
Expand All @@ -149,7 +172,10 @@ function BankAccountStep(props) {
icon={Expensicons.Connect}
title={props.translate('bankAccount.connectManually')}
disabled={!props.user.validated}
onPress={() => BankAccounts.setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL)}
onPress={() => {
removeExistingBankAccountDetails();
BankAccounts.setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL);
}}
shouldShowRightIcon
wrapperStyle={[styles.cardMenuItem]}
/>
Expand Down
Loading
Loading