diff --git a/src/components/TextInputWithLabel.js b/src/components/TextInputWithLabel.js
index 40ac02a9fcbc..310a4a91ca31 100644
--- a/src/components/TextInputWithLabel.js
+++ b/src/components/TextInputWithLabel.js
@@ -54,7 +54,12 @@ const TextInputWithLabel = props => (
)}
diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js
index 28b3075e45ab..8c6522a040c2 100644
--- a/src/libs/ValidationUtils.js
+++ b/src/libs/ValidationUtils.js
@@ -1,7 +1,7 @@
import moment from 'moment';
import CONST from '../CONST';
-import Growl from './Growl';
import {translateLocal} from './translate';
+import {showBankAccountFormValidationError} from './actions/BankAccounts';
/**
* Validating that this is a valid address (PO boxes are not allowed)
@@ -74,27 +74,27 @@ function isValidSSNLastFour(ssnLast4) {
*/
function isValidIdentity(identity) {
if (!isValidAddress(identity.street)) {
- Growl.error(translateLocal('bankAccount.error.address'));
+ showBankAccountFormValidationError(translateLocal('bankAccount.error.address'));
return false;
}
if (identity.state === '') {
- Growl.error(translateLocal('bankAccount.error.addressState'));
+ showBankAccountFormValidationError(translateLocal('bankAccount.error.addressState'));
return false;
}
if (!isValidZipCode(identity.zipCode)) {
- Growl.error(translateLocal('bankAccount.error.zipCode'));
+ showBankAccountFormValidationError(translateLocal('bankAccount.error.zipCode'));
return false;
}
if (!isValidDate(identity.dob)) {
- Growl.error(translateLocal('bankAccount.error.dob'));
+ showBankAccountFormValidationError(translateLocal('bankAccount.error.dob'));
return false;
}
if (!isValidSSNLastFour(identity.ssnLast4)) {
- Growl.error(translateLocal('bankAccount.error.ssnLast4'));
+ showBankAccountFormValidationError(translateLocal('bankAccount.error.ssnLast4'));
return false;
}
diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js
index bd5ebe15bf8e..e0964b1b1a43 100644
--- a/src/libs/actions/BankAccounts.js
+++ b/src/libs/actions/BankAccounts.js
@@ -592,6 +592,10 @@ function validateBankAccount(bankAccountID, validateCode) {
});
}
+function showBankAccountFormValidationError(error) {
+ Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error}).then(() => Growl.error(error));
+}
+
/**
* Create or update the bank account in db with the updated data.
*
@@ -763,7 +767,7 @@ function setupWithdrawalAccount(data) {
goToWithdrawalAccountSetupStep(nextStep, achData);
if (error) {
- Growl.error(error, 5000);
+ showBankAccountFormValidationError(error);
}
})
.catch((response) => {
@@ -773,7 +777,7 @@ function setupWithdrawalAccount(data) {
});
}
-function hideExistingOwnersError() {
+function hideBankAccountErrors() {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error: '', existingOwnersList: ''});
}
@@ -789,5 +793,6 @@ export {
goToWithdrawalAccountSetupStep,
setupWithdrawalAccount,
validateBankAccount,
- hideExistingOwnersError,
+ hideBankAccountErrors,
+ showBankAccountFormValidationError,
};
diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js
index bcedfdb74cd2..3fe264dc5e4a 100644
--- a/src/pages/ReimbursementAccount/BankAccountStep.js
+++ b/src/pages/ReimbursementAccount/BankAccountStep.js
@@ -23,7 +23,7 @@ import Text from '../../components/Text';
import ExpensiTextInput from '../../components/ExpensiTextInput';
import {
goToWithdrawalAccountSetupStep,
- hideExistingOwnersError,
+ hideBankAccountErrors,
setupWithdrawalAccount,
} from '../../libs/actions/BankAccounts';
import ConfirmModal from '../../components/ConfirmModal';
@@ -130,8 +130,8 @@ class BankAccountStep extends React.Component {
const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID;
const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid;
const existingOwners = this.props.reimbursementAccount.existingOwners;
- const isExistingOwnersErrorVisible = Boolean(this.props.reimbursementAccount.error
- && existingOwners);
+ const error = this.props.reimbursementAccount.error;
+ const isExistingOwnersErrorVisible = Boolean(error && existingOwners);
return (
this.setState({routingNumber})}
+ onChangeText={(routingNumber) => {
+ if (error === this.props.translate('bankAccount.error.routingNumber')) {
+ hideBankAccountErrors();
+ }
+ this.setState({routingNumber});
+ }}
disabled={shouldDisableInputs}
+ errorText={error === this.props.translate('bankAccount.error.routingNumber')
+ ? error : ''}
/>
diff --git a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js
index 8562fbef130a..e86f22f44bf4 100644
--- a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js
+++ b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js
@@ -2,6 +2,7 @@ import _ from 'underscore';
import React from 'react';
import PropTypes from 'prop-types';
import {ScrollView, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
import Text from '../../components/Text';
import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import styles from '../../styles/styles';
@@ -11,17 +12,28 @@ import Button from '../../components/Button';
import IdentityForm from './IdentityForm';
import FixedFooter from '../../components/FixedFooter';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts';
+import {
+ goToWithdrawalAccountSetupStep,
+ setupWithdrawalAccount,
+} from '../../libs/actions/BankAccounts';
import Navigation from '../../libs/Navigation/Navigation';
import CONST from '../../CONST';
import {isValidIdentity} from '../../libs/ValidationUtils';
import Growl from '../../libs/Growl';
+import ONYXKEYS from '../../ONYXKEYS';
+import compose from '../../libs/compose';
const propTypes = {
/** Name of the company */
companyName: PropTypes.string.isRequired,
...withLocalizePropTypes,
+
+ /** Bank account currently in setup */
+ reimbursementAccount: PropTypes.shape({
+ /** Error set when handling the API response */
+ error: PropTypes.string,
+ }).isRequired,
};
class BeneficialOwnersStep extends React.Component {
@@ -172,6 +184,7 @@ class BeneficialOwnersStep extends React.Component {
dob: owner.dob || '',
ssnLast4: owner.ssnLast4 || '',
}}
+ error={this.props.reimbursementAccount.error}
/>
{this.state.beneficialOwners.length > 1 && (
this.removeBeneficialOwner(owner)}>
@@ -230,5 +243,11 @@ class BeneficialOwnersStep extends React.Component {
}
BeneficialOwnersStep.propTypes = propTypes;
-
-export default withLocalize(BeneficialOwnersStep);
+export default compose(
+ withLocalize,
+ withOnyx({
+ reimbursementAccount: {
+ key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
+ },
+ }),
+)(BeneficialOwnersStep);
diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js
index 5260a4ff1306..3b7a51563df2 100644
--- a/src/pages/ReimbursementAccount/CompanyStep.js
+++ b/src/pages/ReimbursementAccount/CompanyStep.js
@@ -4,9 +4,15 @@ import React from 'react';
import {View, ScrollView} from 'react-native';
import Str from 'expensify-common/lib/str';
import moment from 'moment';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import CONST from '../../CONST';
-import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts';
+import {
+ goToWithdrawalAccountSetupStep, hideBankAccountErrors,
+ setupWithdrawalAccount,
+ showBankAccountFormValidationError,
+} from '../../libs/actions/BankAccounts';
import Navigation from '../../libs/Navigation/Navigation';
import Text from '../../components/Text';
import ExpensiTextInput from '../../components/ExpensiTextInput';
@@ -20,9 +26,21 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize
import {
isValidAddress, isValidDate, isValidIndustryCode, isValidZipCode,
} from '../../libs/ValidationUtils';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
import ConfirmModal from '../../components/ConfirmModal';
import ExpensiPicker from '../../components/ExpensiPicker';
+const propTypes = {
+ /** Bank account currently in setup */
+ reimbursementAccount: PropTypes.shape({
+ /** Error set when handling the API response */
+ error: PropTypes.string,
+ }).isRequired,
+
+ ...withLocalizePropTypes,
+};
+
class CompanyStep extends React.Component {
constructor(props) {
super(props);
@@ -68,38 +86,47 @@ class CompanyStep extends React.Component {
*/
validate() {
if (!this.state.password.trim()) {
+ showBankAccountFormValidationError(this.props.translate('common.passwordCannotBeBlank'));
return false;
}
if (!isValidAddress(this.state.addressStreet)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressStreet'));
return false;
}
if (this.state.addressState === '') {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressState'));
return false;
}
if (!isValidZipCode(this.state.addressZipCode)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.zipCode'));
return false;
}
if (!Str.isValidURL(this.state.website)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.website'));
return false;
}
if (!/[0-9]{9}/.test(this.state.companyTaxID)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.taxID'));
return false;
}
if (!isValidDate(this.state.incorporationDate)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.incorporationDate'));
return false;
}
if (!isValidIndustryCode(this.state.industryCode)) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.industryCode'));
return false;
}
if (!this.state.hasNoConnectionToCannabis) {
+ showBankAccountFormValidationError(this.props.translate('bankAccount.error.restrictedBusiness'));
return false;
}
@@ -121,6 +148,7 @@ class CompanyStep extends React.Component {
const shouldDisableCompanyTaxID = Boolean(this.props.achData.bankAccountID && this.props.achData.companyTaxID);
const missingRequiredFields = this.requiredFields.reduce((acc, curr) => acc || !this.state[curr].trim(), false);
const shouldDisableSubmitButton = !this.state.hasNoConnectionToCannabis || missingRequiredFields;
+ const error = this.props.reimbursementAccount.error;
return (
<>
@@ -143,8 +171,16 @@ class CompanyStep extends React.Component {
this.setState({addressStreet})}
+ onChangeText={(addressStreet) => {
+ if (error === this.props.translate('bankAccount.error.addressStreet')) {
+ hideBankAccountErrors();
+ }
+ this.setState({addressStreet});
+ }}
value={this.state.addressStreet}
+ errorText={error === this.props.translate('bankAccount.error.addressStreet')
+ ? this.props.translate('bankAccount.error.addressStreet')
+ : ''}
/>
@@ -165,8 +201,16 @@ class CompanyStep extends React.Component {
this.setState({addressZipCode})}
+ onChangeText={(addressZipCode) => {
+ if (error === this.props.translate('bankAccount.error.zipCode')) {
+ hideBankAccountErrors();
+ }
+ this.setState({addressZipCode});
+ }}
value={this.state.addressZipCode}
+ errorText={error === this.props.translate('bankAccount.error.zipCode')
+ ? this.props.translate('bankAccount.error.zipCode')
+ : ''}
/>
this.setState({website})}
+ onChangeText={(website) => {
+ if (error === this.props.translate('bankAccount.error.website')) {
+ hideBankAccountErrors();
+ }
+ this.setState({website});
+ }}
value={this.state.website}
+ errorText={error === this.props.translate('bankAccount.error.website')
+ ? this.props.translate('bankAccount.error.website')
+ : ''}
/>
this.setState({companyTaxID})}
+ onChangeText={(companyTaxID) => {
+ if (error === this.props.translate('bankAccount.error.taxID')) {
+ hideBankAccountErrors();
+ }
+ this.setState({companyTaxID});
+ }}
value={this.state.companyTaxID}
disabled={shouldDisableCompanyTaxID}
+ errorText={error === this.props.translate('bankAccount.error.taxID')
+ ? this.props.translate('bankAccount.error.taxID')
+ : ''}
/>
this.setState({incorporationDate})}
+ onChangeText={(incorporationDate) => {
+ if (error === this.props.translate('bankAccount.error.incorporationDate')) {
+ hideBankAccountErrors();
+ }
+ this.setState({incorporationDate});
+ }}
value={this.state.incorporationDate}
placeholder={this.props.translate('companyStep.incorporationDatePlaceholder')}
+ errorText={error === this.props.translate('bankAccount.error.incorporationDate')
+ ? this.props.translate('bankAccount.error.incorporationDate')
+ : ''}
/>
@@ -223,8 +291,16 @@ class CompanyStep extends React.Component {
helpLinkText={this.props.translate('common.whatThis')}
helpLinkURL="https://www.naics.com/search/"
containerStyles={[styles.mt4]}
- onChangeText={industryCode => this.setState({industryCode})}
+ onChangeText={(industryCode) => {
+ if (error === this.props.translate('bankAccount.error.industryCode')) {
+ hideBankAccountErrors();
+ }
+ this.setState({industryCode});
+ }}
value={this.state.industryCode}
+ errorText={error === this.props.translate('bankAccount.error.industryCode')
+ ? this.props.translate('bankAccount.error.industryCode')
+ : ''}
/>
this.setState({password})}
+ onChangeText={(password) => {
+ if (error === this.props.translate('common.passwordCannotBeBlank')) {
+ hideBankAccountErrors();
+ }
+ this.setState({password});
+ }}
value={this.state.password}
onSubmitEditing={this.submit}
+ errorText={error === this.props.translate('common.passwordCannotBeBlank')
+ ? this.props.translate('common.passwordCannotBeBlank')
+ : ''}
/>
{
const {
firstName, lastName, street, city, state, zipCode, dob, ssnLast4,
@@ -87,19 +93,37 @@ const IdentityForm = ({
containerStyles={[styles.mt4]}
placeholder={translate('common.dateFormat')}
value={dob}
- onChangeText={val => onFieldChange('dob', val)}
+ onChangeText={(val) => {
+ if (error === translateLocal('bankAccount.error.dob')) {
+ hideBankAccountErrors();
+ }
+ onFieldChange('dob', val);
+ }}
+ errorText={error === translateLocal('bankAccount.error.dob') ? error : ''}
/>
onFieldChange('ssnLast4', val)}
+ onChangeText={(val) => {
+ if (error === translateLocal('bankAccount.error.ssnLast4')) {
+ hideBankAccountErrors();
+ }
+ onFieldChange('ssnLast4', val);
+ }}
+ errorText={error === translateLocal('bankAccount.error.ssnLast4') ? error : ''}
/>
onFieldChange('street', val)}
+ onChangeText={(val) => {
+ if (error === translateLocal('bankAccount.error.address')) {
+ hideBankAccountErrors();
+ }
+ onFieldChange('street', val);
+ }}
+ errorText={error === translateLocal('bankAccount.error.address') ? error : ''}
/>
@@ -121,7 +145,13 @@ const IdentityForm = ({
label={translate('common.zip')}
containerStyles={[styles.mt4]}
value={zipCode}
- onChangeText={val => onFieldChange('zipCode', val)}
+ onChangeText={(val) => {
+ if (error === translateLocal('bankAccount.error.zipCode')) {
+ hideBankAccountErrors();
+ }
+ onFieldChange('zipCode', val);
+ }}
+ errorText={error === translateLocal('bankAccount.error.zipCode') ? error : ''}
/>
);
diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js
index 2287724daa9b..122b5825acbf 100644
--- a/src/pages/ReimbursementAccount/RequestorStep.js
+++ b/src/pages/ReimbursementAccount/RequestorStep.js
@@ -1,6 +1,8 @@
import React from 'react';
import lodashGet from 'lodash/get';
import {View, ScrollView} from 'react-native';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
import styles from '../../styles/styles';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
@@ -9,13 +11,28 @@ import TextLink from '../../components/TextLink';
import Navigation from '../../libs/Navigation/Navigation';
import CheckboxWithLabel from '../../components/CheckboxWithLabel';
import Text from '../../components/Text';
-import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts';
+import {
+ goToWithdrawalAccountSetupStep,
+ setupWithdrawalAccount,
+} from '../../libs/actions/BankAccounts';
import Button from '../../components/Button';
import FixedFooter from '../../components/FixedFooter';
import IdentityForm from './IdentityForm';
import {isValidIdentity} from '../../libs/ValidationUtils';
import Growl from '../../libs/Growl';
import Onfido from '../../components/Onfido';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
+
+const propTypes = {
+ /** Bank account currently in setup */
+ reimbursementAccount: PropTypes.shape({
+ /** Error set when handling the API response */
+ error: PropTypes.string,
+ }).isRequired,
+
+ ...withLocalizePropTypes,
+};
class RequestorStep extends React.Component {
constructor(props) {
@@ -116,6 +133,7 @@ class RequestorStep extends React.Component {
dob: this.state.dob,
ssnLast4: this.state.ssnLast4,
}}
+ error={this.props.reimbursementAccount.error}
/>