diff --git a/assets/images/bank.svg b/assets/images/bank.svg
new file mode 100644
index 000000000000..4e17ec42c591
--- /dev/null
+++ b/assets/images/bank.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/images/example-check-image.png b/assets/images/example-check-image.png
new file mode 100644
index 000000000000..c6ef809ed983
Binary files /dev/null and b/assets/images/example-check-image.png differ
diff --git a/assets/images/paycheck.svg b/assets/images/paycheck.svg
new file mode 100644
index 000000000000..231545aec85d
--- /dev/null
+++ b/assets/images/paycheck.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/CONST.js b/src/CONST.js
index 71a80cf4f0b7..52c6ec618333 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -6,6 +6,16 @@ const CONST = {
IOS: 'https://apps.apple.com/us/app/expensify-cash/id1530278510',
DESKTOP: 'https://expensify.cash/Expensify.cash.dmg',
},
+ BANK_ACCOUNT: {
+ ADD_METHOD: {
+ MANUAL: 'manual',
+ PLAID: 'plaid',
+ },
+ REGEX: {
+ IBAN: /^[A-Za-z0-9]{2,30}$/,
+ SWIFT_BIC: /^[A-Za-z0-9]{8,11}$/,
+ },
+ },
BETAS: {
ALL: 'all',
CHRONOS_IN_CASH: 'chronosInCash',
diff --git a/src/ROUTES.js b/src/ROUTES.js
index 0a84cb15ed98..8fbb80f1853c 100644
--- a/src/ROUTES.js
+++ b/src/ROUTES.js
@@ -9,6 +9,7 @@ const REPORT = 'r';
export default {
ADD_PERSONAL_BANK_ACCOUNT: 'add-personal-bank-account',
+ BANK_ACCOUNT_NEW: 'bank-account/new',
HOME: '',
SETTINGS: 'settings',
SETTINGS_PROFILE: 'settings/profile',
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
new file mode 100644
index 000000000000..1743eaeb3d82
--- /dev/null
+++ b/src/components/AddPlaidBankAccount.js
@@ -0,0 +1,202 @@
+import _ from 'underscore';
+import React from 'react';
+import {
+ ActivityIndicator,
+ View,
+ TextInput,
+} from 'react-native';
+import PropTypes from 'prop-types';
+import lodashGet from 'lodash/get';
+import {withOnyx} from 'react-native-onyx';
+import PlaidLink from './PlaidLink';
+import {
+ clearPlaidBankAccountsAndToken,
+ fetchPlaidLinkToken,
+ getPlaidBankAccounts,
+} from '../libs/actions/BankAccounts';
+import ONYXKEYS from '../ONYXKEYS';
+import styles from '../styles/styles';
+import canFocusInputOnScreenFocus from '../libs/canFocusInputOnScreenFocus';
+import compose from '../libs/compose';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import Button from './Button';
+import Picker from './Picker';
+import Icon from './Icon';
+import {DownArrow} from './Icon/Expensicons';
+import Text from './Text';
+
+const propTypes = {
+ ...withLocalizePropTypes,
+
+ /** Plaid SDK token to use to initialize the widget */
+ plaidLinkToken: PropTypes.string,
+
+ /** Contains list of accounts and loading state while fetching them */
+ plaidBankAccounts: PropTypes.shape({
+ /** Whether we are fetching the bank accounts from the API */
+ loading: PropTypes.bool,
+
+ /** List of accounts */
+ accounts: PropTypes.arrayOf(PropTypes.object),
+ }),
+
+ /** Fired when the user exits the Plaid flow */
+ onExitPlaid: PropTypes.func,
+
+ /** Fired when the user selects an account and submits the form */
+ onSubmit: PropTypes.func,
+
+ /** Additional text to display */
+ text: PropTypes.string,
+};
+
+const defaultProps = {
+ plaidLinkToken: '',
+ plaidBankAccounts: {
+ loading: false,
+ },
+ onExitPlaid: () => {},
+ onSubmit: () => {},
+ text: '',
+};
+
+class AddPlaidBankAccount extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.selectAccount = this.selectAccount.bind(this);
+
+ this.state = {
+ selectedIndex: undefined,
+ password: '',
+ isCreatingAccount: false,
+ institution: {},
+ };
+ }
+
+ componentDidMount() {
+ clearPlaidBankAccountsAndToken();
+ fetchPlaidLinkToken();
+ }
+
+ /**
+ * Get list of bank accounts
+ *
+ * @returns {Object[]}
+ */
+ getAccounts() {
+ return lodashGet(this.props.plaidBankAccounts, 'accounts', []);
+ }
+
+ selectAccount() {
+ const account = this.getAccounts()[this.state.selectedIndex];
+ this.props.onSubmit({
+ account, password: this.state.password, plaidLinkToken: this.props.plaidLinkToken,
+ });
+ this.setState({isCreatingAccount: true});
+ }
+
+ render() {
+ const accounts = this.getAccounts();
+ const options = _.chain(accounts)
+ .filter(account => !account.alreadyExists)
+ .map((account, index) => ({
+ value: index, label: `${account.addressName} ${account.accountNumber}`,
+ }))
+ .value();
+
+ return (
+ <>
+ {(!this.props.plaidLinkToken || this.props.plaidBankAccounts.loading)
+ && (
+
+
+
+ )}
+ {!_.isEmpty(this.props.plaidLinkToken) && (
+ {
+ getPlaidBankAccounts(publicToken, metadata.institution.name);
+ this.setState({institution: metadata.institution});
+ }}
+ onError={(error) => {
+ console.debug(`Plaid Error: ${error.message}`);
+ }}
+
+ // User prematurely exited the Plaid flow
+ // eslint-disable-next-line react/jsx-props-no-multi-spaces
+ onExit={this.props.onExitPlaid}
+ />
+ )}
+ {accounts.length > 0 && (
+ <>
+
+ {!_.isEmpty(this.props.text) && (
+ {this.props.text}
+ )}
+ {/* @TODO there are a bunch of logos to incorporate here to replace this name
+ https://d2k5nsl2zxldvw.cloudfront.net/images/plaid/bg_plaidLogos_12@2x.png */}
+ {this.state.institution.name}
+
+ {
+ this.setState({selectedIndex: Number(index)});
+ }}
+ items={options}
+ placeholder={_.isUndefined(this.state.selectedIndex) ? {
+ value: '',
+ label: this.props.translate('bankAccount.chooseAnAccount'),
+ } : {}}
+ value={this.state.selectedIndex}
+ icon={() => }
+ />
+
+ {!_.isUndefined(this.state.selectedIndex) && (
+
+
+ {this.props.translate('addPersonalBankAccountPage.enterPassword')}
+
+ this.setState({password: text})}
+ />
+
+ )}
+
+
+
+
+ >
+ )}
+ >
+ );
+ }
+}
+
+AddPlaidBankAccount.propTypes = propTypes;
+AddPlaidBankAccount.defaultProps = defaultProps;
+
+export default compose(
+ withLocalize,
+ withOnyx({
+ plaidLinkToken: {
+ key: ONYXKEYS.PLAID_LINK_TOKEN,
+ },
+ plaidBankAccounts: {
+ key: ONYXKEYS.PLAID_BANK_ACCOUNTS,
+ },
+ }),
+)(AddPlaidBankAccount);
diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js
index 5d42345e0b42..6cdbac6db739 100644
--- a/src/components/Checkbox.js
+++ b/src/components/Checkbox.js
@@ -9,8 +9,8 @@ const propTypes = {
/** Whether checkbox is checked */
isChecked: PropTypes.bool.isRequired,
- /** A function that is called when the box/label is clicked on */
- onClick: PropTypes.func.isRequired,
+ /** A function that is called when the box/label is pressed */
+ onPress: PropTypes.func.isRequired,
/** Text that appears next to check box */
label: PropTypes.string,
@@ -22,17 +22,17 @@ const defaultProps = {
const Checkbox = ({
isChecked,
- onClick,
+ onPress,
label,
}) => (
- onClick(!isChecked)}>
+ onPress(!isChecked)}>
{label && (
- onClick(!isChecked)}>
+ onPress(!isChecked)}>
{label}
diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js
new file mode 100644
index 000000000000..327beed2a74f
--- /dev/null
+++ b/src/components/CheckboxWithLabel.js
@@ -0,0 +1,58 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {View, TouchableOpacity} from 'react-native';
+import _ from 'underscore';
+import styles from '../styles/styles';
+import Checkbox from './Checkbox';
+
+const propTypes = {
+ /** Component to display for label */
+ LabelComponent: PropTypes.func.isRequired,
+
+ /** Whether the checkbox is checked */
+ isChecked: PropTypes.bool.isRequired,
+
+ /** Called when the checkbox or label is pressed */
+ onPress: PropTypes.func.isRequired,
+
+ /** Container styles */
+ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+};
+
+const defaultProps = {
+ style: [],
+};
+
+const CheckboxWithLabel = ({
+ LabelComponent, isChecked, onPress, style,
+}) => {
+ const defaultStyles = [styles.flexRow];
+ const wrapperStyles = _.isArray(style) ? [...defaultStyles, ...style] : [...defaultStyles, style];
+ return (
+
+
+
+
+
+
+ );
+};
+
+CheckboxWithLabel.propTypes = propTypes;
+CheckboxWithLabel.defaultProps = defaultProps;
+CheckboxWithLabel.displayName = 'CheckboxWithLabel';
+
+export default CheckboxWithLabel;
diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js
index a5fcafc3185c..6a8f9dccfb46 100644
--- a/src/components/Icon/Expensicons.js
+++ b/src/components/Icon/Expensicons.js
@@ -2,6 +2,7 @@ import Android from '../../../assets/images/android.svg';
import Apple from '../../../assets/images/apple.svg';
import ArrowRight from '../../../assets/images/arrow-right.svg';
import BackArrow from '../../../assets/images/back-left.svg';
+import Bank from '../../../assets/images/bank.svg';
import Bug from '../../../assets/images/bug.svg';
import Camera from '../../../assets/images/camera.svg';
import ChatBubble from '../../../assets/images/chatbubble.svg';
@@ -27,6 +28,7 @@ import Monitor from '../../../assets/images/monitor.svg';
import NewWindow from '../../../assets/images/new-window.svg';
import Offline from '../../../assets/images/offline.svg';
import Paperclip from '../../../assets/images/paperclip.svg';
+import Paycheck from '../../../assets/images/paycheck.svg';
import Pencil from '../../../assets/images/pencil.svg';
import Phone from '../../../assets/images/phone.svg';
import Pin from '../../../assets/images/pin.svg';
@@ -47,6 +49,7 @@ export {
Apple,
ArrowRight,
BackArrow,
+ Bank,
Bug,
Camera,
ChatBubble,
@@ -72,6 +75,7 @@ export {
NewWindow,
Offline,
Paperclip,
+ Paycheck,
Pencil,
Phone,
Pin,
diff --git a/src/components/Picker/PickerPropTypes.js b/src/components/Picker/PickerPropTypes.js
index 88a814392af6..ec3a603a54ef 100644
--- a/src/components/Picker/PickerPropTypes.js
+++ b/src/components/Picker/PickerPropTypes.js
@@ -13,7 +13,7 @@ const propTypes = {
/** The items to display in the list of selections */
items: PropTypes.arrayOf(PropTypes.shape({
/** The value of the item that is being selected */
- value: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
/** The text to display for the item */
label: PropTypes.string.isRequired,
diff --git a/src/components/TextInputWithLabel.js b/src/components/TextInputWithLabel.js
index e129dd6fb462..6de98bc9f28b 100644
--- a/src/components/TextInputWithLabel.js
+++ b/src/components/TextInputWithLabel.js
@@ -6,19 +6,20 @@ import styles from '../styles/styles';
const propTypes = {
/** Label text */
- label: PropTypes.string.isRequired,
+ label: PropTypes.string,
/** Text to show if there is an error */
errorText: PropTypes.string,
};
const defaultProps = {
+ label: '',
errorText: '',
};
const TextInputWithLabel = props => (
<>
- {props.label}
+ {!_.isEmpty(props.label) && {props.label}}
{
href={props.href}
>
{({hovered, pressed}) => (
-
+
{props.children}
)}
diff --git a/src/languages/en.js b/src/languages/en.js
index cfe1a9790ade..c4404fc8bcec 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -26,12 +26,15 @@ export default {
email: 'Email',
and: 'and',
details: 'Details',
+ privacy: 'Privacy',
privacyPolicy: 'Privacy Policy',
delete: 'Delete',
contacts: 'Contacts',
recents: 'Recents',
close: 'Close',
+ saveAndContinue: 'Save & Continue',
settings: 'Settings',
+ termsOfService: 'Terms of Service',
},
attachmentPicker: {
cameraPermissionRequired: 'Camera Permission Required',
@@ -254,11 +257,22 @@ export default {
enterPassword: 'Enter a password',
setPassword: 'Set Password',
},
+ bankAccount: {
+ accountNumber: 'Account Number',
+ routingNumber: 'Routing Number',
+ addBankAccount: 'Add Bank Account',
+ chooseAnAccount: 'Choose an Account',
+ logIntoYourBank: 'Log Into Your Bank',
+ connectManually: 'Connect Manually',
+ yourDataIsSecure: 'Your data is secure',
+ toGetStarted: 'To get started with the Expensify Card, you first need to add a bank account.',
+ 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.',
+ iAcceptThe: 'I accept the ',
+ },
addPersonalBankAccountPage: {
enterPassword: 'Enter password',
- addPersonalBankAccount: 'Add Bank Account',
alreadyAdded: 'This account has already been added.',
- selectAccount: 'Select an account:',
},
attachmentView: {
unknownFilename: 'Unknown Filename',
@@ -279,7 +293,6 @@ export default {
onfidoStep: {
acceptTerms: 'By continuing with the request to activate your Expensify wallet, you confirm that you have read, understand and accept ',
facialScan: 'Onfido’s Facial Scan Policy and Release',
- termsOfService: 'Terms of Service',
tryAgain: 'Try Again',
verifyIdentity: 'Verify Identity',
genericError: 'There was an error while processing this step. Please try again.',
diff --git a/src/languages/es.js b/src/languages/es.js
index a199c313d8da..252d96d898cd 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -29,7 +29,9 @@ export default {
delete: 'Eliminar',
contacts: 'Contactos',
recents: 'Recientes',
+ saveAndContinue: 'Guardar y Continuar',
settings: 'Configuración',
+ termsOfService: 'Términos de servicio',
},
attachmentPicker: {
cameraPermissionRequired: 'Se necesita permiso para usar la cámara',
@@ -250,11 +252,22 @@ export default {
enterPassword: 'Escribe una contraseña',
setPassword: 'Configura tu Contraseña',
},
+ bankAccount: {
+ accountNumber: 'Número de cuenta',
+ routingNumber: 'Número de ruta',
+ addBankAccount: 'Agregar cuenta bancaria',
+ chooseAnAccount: 'Elige una cuenta',
+ logIntoYourBank: 'Inicie sesión en su banco',
+ connectManually: 'Conectar manualmente',
+ yourDataIsSecure: 'Tus datos estan seguros',
+ toGetStarted: 'Para comenzar con la tarjeta Expensify, primero debe agregar una cuenta bancaria.',
+ 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 para la cuenta.',
+ iAcceptThe: 'Acepto los ',
+ },
addPersonalBankAccountPage: {
enterPassword: 'Escribe una contraseña',
- addPersonalBankAccount: 'Agregar cuenta bancaria',
alreadyAdded: 'Esta cuenta ya ha sido agregada.',
- selectAccount: 'Selecciona una cuenta:',
},
attachmentView: {
unknownFilename: 'Archivo desconocido',
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index a032193f97f8..a8c87634c68d 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -49,6 +49,7 @@ import {
NewChatModalStackNavigator,
SettingsModalStackNavigator,
EnablePaymentsStackNavigator,
+ BusinessBankAccountModalStackNavigator,
AddPersonalBankAccountModalStackNavigator,
} from './ModalStackNavigators';
import SCREENS from '../../../SCREENS';
@@ -275,6 +276,12 @@ class AuthScreens extends React.Component {
component={AddPersonalBankAccountModalStackNavigator}
listeners={modalScreenListeners}
/>
+
);
}
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 7a3685f25067..f7de075cea8f 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -20,6 +20,7 @@ import SettingsAddSecondaryLoginPage from '../../../pages/settings/AddSecondaryL
import IOUCurrencySelection from '../../../pages/iou/IOUCurrencySelection';
import ReportParticipantsPage from '../../../pages/ReportParticipantsPage';
import EnablePaymentsPage from '../../../pages/EnablePayments';
+import BusinessBankAccountNewPage from '../../../pages/BusinessBankAccount/NewPage';
import AddPersonalBankAccountPage from '../../../pages/AddPersonalBankAccountPage';
const defaultSubRouteOptions = {
@@ -152,6 +153,13 @@ const AddPersonalBankAccountModalStackNavigator = createModalStackNavigator([{
name: 'AddPersonalBankAccount_Root',
}]);
+const BusinessBankAccountModalStackNavigator = createModalStackNavigator([
+ {
+ Component: BusinessBankAccountNewPage,
+ name: 'BusinessBankAccount_New',
+ },
+]);
+
export {
IOUBillStackNavigator,
IOURequestModalStackNavigator,
@@ -163,5 +171,6 @@ export {
NewChatModalStackNavigator,
SettingsModalStackNavigator,
EnablePaymentsStackNavigator,
+ BusinessBankAccountModalStackNavigator,
AddPersonalBankAccountModalStackNavigator,
};
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index 7053c8d4f021..720196767e8b 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -109,6 +109,11 @@ export default {
AddPersonalBankAccount_Root: ROUTES.ADD_PERSONAL_BANK_ACCOUNT,
},
},
+ BusinessBankAccount: {
+ screens: {
+ BusinessBankAccount_New: ROUTES.BANK_ACCOUNT_NEW,
+ },
+ },
EnablePayments: {
screens: {
EnablePayments_Root: ROUTES.ENABLE_PAYMENTS,
diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js
index 0b9e2f9e6ee9..3312d0c0723c 100644
--- a/src/libs/actions/BankAccounts.js
+++ b/src/libs/actions/BankAccounts.js
@@ -62,10 +62,11 @@ function getPlaidBankAccounts(publicToken, bank) {
/**
* We clear these out of storage once we are done with them so the user must re-enter Plaid credentials upon returning.
*/
-function clearPlaidBankAccounts() {
+function clearPlaidBankAccountsAndToken() {
plaidBankAccounts = [];
bankName = '';
Onyx.set(ONYXKEYS.PLAID_BANK_ACCOUNTS, {});
+ Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, null);
}
/**
@@ -273,7 +274,7 @@ export {
fetchPlaidLinkToken,
addPlaidBankAccount,
getPlaidBankAccounts,
- clearPlaidBankAccounts,
+ clearPlaidBankAccountsAndToken,
fetchOnfidoToken,
activateWallet,
fetchUserWallet,
diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js
index 9fb582421717..f82546dc1f73 100644
--- a/src/pages/AddPersonalBankAccountPage.js
+++ b/src/pages/AddPersonalBankAccountPage.js
@@ -1,190 +1,31 @@
-import _ from 'underscore';
import React from 'react';
-import {
- ActivityIndicator,
- View,
- Text,
- TextInput,
-} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import {withOnyx} from 'react-native-onyx';
import HeaderWithCloseButton from '../components/HeaderWithCloseButton';
import ScreenWrapper from '../components/ScreenWrapper';
import Navigation from '../libs/Navigation/Navigation';
-import PlaidLink from '../components/PlaidLink';
import {
addPlaidBankAccount,
- clearPlaidBankAccounts,
- fetchPlaidLinkToken,
- getPlaidBankAccounts,
} from '../libs/actions/BankAccounts';
-import ONYXKEYS from '../ONYXKEYS';
-import OptionRow from './home/sidebar/OptionRow';
-import styles from '../styles/styles';
-import canFocusInputOnScreenFocus from '../libs/canFocusInputOnScreenFocus';
-import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import Button from '../components/Button';
+import AddPlaidBankAccount from '../components/AddPlaidBankAccount';
const propTypes = {
...withLocalizePropTypes,
-
- // Plaid SDK token to use to initialize the widget
- plaidLinkToken: PropTypes.string,
-
- // Contains list of accounts and loading state while fetching them
- plaidBankAccounts: PropTypes.shape({
- // Whether we are fetching the bank accounts from the API
- loading: PropTypes.bool,
-
- // List of accounts
- accounts: PropTypes.arrayOf(PropTypes.object),
- }),
};
-const defaultProps = {
- plaidLinkToken: '',
- plaidBankAccounts: {
- loading: false,
- },
-};
-
-class AddPersonalBankAccountPage extends React.Component {
- constructor(props) {
- super(props);
-
- this.addSelectedAccount = this.addSelectedAccount.bind(this);
-
- this.state = {
- selectedIndex: undefined,
- password: '',
- isCreatingAccount: false,
- };
- }
-
- componentDidMount() {
- clearPlaidBankAccounts();
- fetchPlaidLinkToken();
- }
-
- /**
- * Get list of bank accounts
- *
- * @returns {Object[]}
- */
- getAccounts() {
- return lodashGet(this.props.plaidBankAccounts, 'accounts', []);
- }
-
- addSelectedAccount() {
- const account = this.getAccounts()[this.state.selectedIndex];
- addPlaidBankAccount(account, this.state.password, this.props.plaidLinkToken);
- this.setState({isCreatingAccount: true});
- }
-
- render() {
- const accounts = this.getAccounts();
- return (
-
- Navigation.dismissModal()}
- />
- {(!this.props.plaidLinkToken || this.props.plaidBankAccounts.loading)
- && }
- {!_.isEmpty(this.props.plaidLinkToken) && (
- {
- getPlaidBankAccounts(publicToken, metadata.institution.name);
- }}
- onError={(error) => {
- console.debug(`Plaid Error: ${error.message}`);
- }}
- onExit={() => {
- // If the user prematurely exits the Plaid flow then let's kick them back to the main app
- Navigation.dismissModal();
- }}
- />
- )}
- {accounts.length > 0 && (
-
-
- {this.props.translate('addPersonalBankAccountPage.selectAccount')}
-
- {_.map(accounts, (account, index) => (
-
- {
- if (account.alreadyExists) {
- return;
- }
-
- this.setState({selectedIndex: index});
- }}
- />
- {account.alreadyExists && (
-
- {this.props.translate('addPersonalBankAccountPage.alreadyAdded')}
-
- )}
-
- ))}
-
- {!_.isUndefined(this.state.selectedIndex) && (
- <>
-
- {this.props.translate('addPersonalBankAccountPage.enterPassword')}
-
- this.setState({password: text})}
- />
- >
- )}
-
-
-
- )}
-
- );
- }
-}
+const AddPersonalBankAccountPage = props => (
+
+
+ {
+ addPlaidBankAccount(account, password, plaidLinkToken);
+ }}
+ onExitPlaid={Navigation.dismissModal}
+ />
+
+);
AddPersonalBankAccountPage.propTypes = propTypes;
-AddPersonalBankAccountPage.defaultProps = defaultProps;
-
-export default compose(
- withLocalize,
- withOnyx({
- plaidLinkToken: {
- key: ONYXKEYS.PLAID_LINK_TOKEN,
- },
- plaidBankAccounts: {
- key: ONYXKEYS.PLAID_BANK_ACCOUNTS,
- },
- }),
-)(AddPersonalBankAccountPage);
+export default withLocalize(AddPersonalBankAccountPage);
diff --git a/src/pages/BusinessBankAccount/NewPage.js b/src/pages/BusinessBankAccount/NewPage.js
new file mode 100644
index 000000000000..7e0bf0fd27c0
--- /dev/null
+++ b/src/pages/BusinessBankAccount/NewPage.js
@@ -0,0 +1,202 @@
+import _ from 'underscore';
+import React from 'react';
+import PropTypes from 'prop-types';
+import {View, Image} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
+import MenuItem from '../../components/MenuItem';
+import {Paycheck, Bank, Lock} from '../../components/Icon/Expensicons';
+import styles from '../../styles/styles';
+import TextLink from '../../components/TextLink';
+import Button from '../../components/Button';
+import Icon from '../../components/Icon';
+import colors from '../../styles/colors';
+import Navigation from '../../libs/Navigation/Navigation';
+import Permissions from '../../libs/Permissions';
+import CONST from '../../CONST';
+import TextInputWithLabel from '../../components/TextInputWithLabel';
+import AddPlaidBankAccount from '../../components/AddPlaidBankAccount';
+import ONYXKEYS from '../../ONYXKEYS';
+import CheckboxWithLabel from '../../components/CheckboxWithLabel';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import compose from '../../libs/compose';
+import exampleCheckImage from '../../../assets/images/example-check-image.png';
+import Text from '../../components/Text';
+
+const propTypes = {
+ /** List of betas */
+ betas: PropTypes.arrayOf(PropTypes.string).isRequired,
+
+ ...withLocalizePropTypes,
+};
+
+class BusinessBankAccountNewPage extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.toggleTerms = this.toggleTerms.bind(this);
+ this.addManualAccount = this.addManualAccount.bind(this);
+
+ this.state = {
+ // One of CONST.BANK_ACCOUNT.ADD_METHOD
+ bankAccountAddMethod: undefined,
+ hasAcceptedTerms: false,
+ routingNumber: '',
+ accountNumber: '',
+ };
+ }
+
+ toggleTerms() {
+ this.setState(prevState => ({
+ hasAcceptedTerms: !prevState.hasAcceptedTerms,
+ }));
+ }
+
+ /**
+ * @returns {Boolean}
+ */
+ canSubmitManually() {
+ return this.state.hasAcceptedTerms
+
+ // These are taken from BankCountry.js in Web-Secure
+ && CONST.BANK_ACCOUNT.REGEX.IBAN.test(this.state.accountNumber.trim())
+ && CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(this.state.routingNumber.trim());
+ }
+
+ addManualAccount() {
+ // @TODO call API to add account manually
+ }
+
+ render() {
+ if (!Permissions.canUseFreePlan(this.props.betas)) {
+ console.debug('Not showing new bank account page because user is not on free plan beta');
+ Navigation.dismissModal();
+ return null;
+ }
+
+ return (
+
+
+ this.setState({bankAccountAddMethod: undefined})}
+ shouldShowBackButton={!_.isUndefined(this.state.bankAccountAddMethod)}
+ />
+ {!this.state.bankAccountAddMethod && (
+ <>
+
+
+ {this.props.translate('bankAccount.toGetStarted')}
+
+
+ >
+ )}
+ {this.state.bankAccountAddMethod === CONST.BANK_ACCOUNT.ADD_METHOD.PLAID && (
+ {
+ console.debug(args);
+ }}
+ onExitPlaid={() => {
+ this.setState({bankAccountAddMethod: undefined});
+ }}
+ />
+ )}
+ {this.state.bankAccountAddMethod === CONST.BANK_ACCOUNT.ADD_METHOD.MANUAL && (
+ <>
+
+
+ {this.props.translate('bankAccount.checkHelpLine')}
+
+
+ this.setState({routingNumber})}
+ />
+ this.setState({accountNumber})}
+ />
+ (
+
+
+ {this.props.translate('bankAccount.iAcceptThe')}
+
+
+ {`Expensify ${this.props.translate('common.termsOfService')}`}
+
+
+ )}
+ />
+
+
+ >
+ )}
+
+
+ );
+ }
+}
+
+BusinessBankAccountNewPage.propTypes = propTypes;
+
+export default compose(
+ withOnyx({
+ betas: {
+ key: ONYXKEYS.BETAS,
+ },
+ }),
+ withLocalize,
+)(BusinessBankAccountNewPage);
diff --git a/src/pages/EnablePayments/OnfidoStep.js b/src/pages/EnablePayments/OnfidoStep.js
index d6c231d41470..49c9000a807d 100644
--- a/src/pages/EnablePayments/OnfidoStep.js
+++ b/src/pages/EnablePayments/OnfidoStep.js
@@ -101,7 +101,7 @@ class OnfidoStep extends React.Component {
- {this.props.translate('onfidoStep.termsOfService')}
+ {this.props.translate('common.termsOfService')}
.
diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.js
index 0286aba8ab3b..38bbadb31ac6 100644
--- a/src/pages/EnablePayments/TermsStep.js
+++ b/src/pages/EnablePayments/TermsStep.js
@@ -1,6 +1,6 @@
import React from 'react';
import {
- View, ScrollView, Text, TouchableOpacity,
+ View, ScrollView,
} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
@@ -8,7 +8,6 @@ import ScreenWrapper from '../../components/ScreenWrapper';
import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import Navigation from '../../libs/Navigation/Navigation';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import Checkbox from '../../components/Checkbox';
import styles from '../../styles/styles';
import Button from '../../components/Button';
import {activateWallet} from '../../libs/actions/BankAccounts';
@@ -16,6 +15,8 @@ import CONST from '../../CONST';
import TextLink from '../../components/TextLink';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
+import CheckboxWithLabel from '../../components/CheckboxWithLabel';
+import Text from '../../components/Text';
const propTypes = {
/** Comes from Onyx. Information about the terms for the wallet */
@@ -56,14 +57,6 @@ class TermsStep extends React.Component {
}
render() {
- const toggleStyles = [
- styles.ml2,
- styles.pr2,
- styles.w100,
- styles.flexRow,
- styles.flexWrap,
- styles.alignItemsCenter,
- ];
return (
-
-
-
+ (
{`${this.props.translate('termsStep.haveReadAndAgree')} `}
@@ -94,32 +83,30 @@ class TermsStep extends React.Component {
{`${this.props.translate('termsStep.electronicDisclosures')}.`}
-
-
-
-
-
-
- {`${this.props.translate('termsStep.agreeToThe')} `}
-
+ )}
+ />
+ (
+ <>
+
+ {`${this.props.translate('termsStep.agreeToThe')} `}
+
-
- {`${this.props.translate('common.privacyPolicy')} `}
-
+
+ {`${this.props.translate('common.privacyPolicy')} `}
+
- {`${this.props.translate('common.and')} `}
+ {`${this.props.translate('common.and')} `}
-
- {`${this.props.translate('termsStep.walletAgreement')}.`}
-
-
-
+
+ {`${this.props.translate('termsStep.walletAgreement')}.`}
+
+ >
+ )}
+ />
{this.state.error && (
{this.props.translate('termsStep.termsMustBeAccepted')}
diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js
index 3d95dd475d61..7fade8151c0c 100755
--- a/src/pages/settings/Profile/ProfilePage.js
+++ b/src/pages/settings/Profile/ProfilePage.js
@@ -381,7 +381,7 @@ class ProfilePage extends Component {
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 170b7fea55c0..3a2fac4347a2 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -985,6 +985,14 @@ const styles = {
borderRightWidth: 0,
},
+ exampleCheckImage: {
+ width: '100%',
+ height: 80,
+ borderColor: themeColors.border,
+ borderWidth: 1,
+ borderRadius: variables.componentBorderRadiusNormal,
+ },
+
singleAvatar: {
height: 24,
width: 24,