From c09bf342661bebd02d0a23f95eb0c0a80297d66f Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Tue, 6 Sep 2022 01:06:37 +0530 Subject: [PATCH 01/13] bank account step form refactored --- src/ONYXKEYS.js | 2 + src/components/AddPlaidBankAccount.js | 5 + .../ReimbursementAccount/BankAccountStep.js | 163 ++++++------------ 3 files changed, 57 insertions(+), 113 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index ab94c4dff47c..995a853489ec 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -171,5 +171,7 @@ export default { FORMS: { ADD_DEBIT_CARD_FORM: 'addDebitCardForm', REQUEST_CALL_FORM: 'requestCallForm', + BANK_ACCOUNT_STEP_FORM_MANUAL: 'bankAccountStepFormManual', + BANK_ACCOUNT_STEP_FORM_PLAID: 'bankAccountStepFormPlaid', }, }; diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index c0f926430b0c..642899cba2fd 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -50,10 +50,14 @@ const propTypes = { /** Are we adding a withdrawal account? */ allowDebit: PropTypes.bool, + /** The ID used to uniquely identify the input in a Form */ + inputID: PropTypes.string, + ...withLocalizePropTypes, }; const defaultProps = { + inputID: undefined, plaidData: { bankName: '', plaidAccessToken: '', @@ -191,6 +195,7 @@ class AddPlaidBankAccount extends React.Component { ReimbursementAccountUtils.getErrorText(this.props, this.errorTranslationKeys, inputKey); - this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); - this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); - } - - toggleTerms() { - this.setState((prevState) => { - const hasAcceptedTerms = !prevState.hasAcceptedTerms; - BankAccounts.updateReimbursementAccountDraft({acceptTerms: hasAcceptedTerms}); - return {hasAcceptedTerms}; - }); - this.clearError('hasAcceptedTerms'); + this.validate = this.validate.bind(this); + this.validatePlaidAccount = this.validatePlaidAccount.bind(this); } /** * @returns {Boolean} */ - validate() { + validate(values) { const errors = {}; - if (!CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(this.state.accountNumber.trim())) { - errors.accountNumber = true; + if (!values.accountNumber || !CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim())) { + errors.accountNumber = this.props.translate('bankAccount.error.accountNumber'); } - if (!CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(this.state.routingNumber.trim()) || !ValidationUtils.isValidRoutingNumber(this.state.routingNumber.trim())) { - errors.routingNumber = true; + if (!values.routingNumber || !CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(values.routingNumber.trim()) || !ValidationUtils.isValidRoutingNumber(values.routingNumber.trim())) { + errors.routingNumber = this.props.translate('bankAccount.error.routingNumber'); } - if (!this.state.hasAcceptedTerms) { - errors.hasAcceptedTerms = true; + if (!values.acceptedTerms) { + errors.acceptedTerms = this.props.translate('common.error.acceptedTerms'); } - BankAccounts.setBankAccountFormValidationErrors(errors); - return _.size(errors) === 0; + return errors; } - /** - * Clear the error associated to inputKey if found and store the inputKey new value in the state. - * - * @param {String} inputKey - * @param {String} value - */ - clearErrorAndSetValue(inputKey, value) { - const newState = {[inputKey]: value}; - this.setState(newState); - BankAccounts.updateReimbursementAccountDraft(newState); - this.clearError(inputKey); - } - addManualAccount() { - if (!this.validate()) { - return; + validatePlaidAccount(values) { + const errors = {}; + if (_.isUndefined(values.selectedPlaidBankAccount)) { + errors.selectedPlaidBankAccount = this.props.translate('bankAccount.error.noBankAccountSelected'); } + return errors; + } + + addManualAccount(values) { BankAccounts.setupWithdrawalAccount({ - acceptTerms: this.state.hasAcceptedTerms, - accountNumber: this.state.accountNumber, - routingNumber: this.state.routingNumber, + acceptTerms: values.acceptedTerms, + accountNumber: values.accountNumber, + routingNumber: values.routingNumber, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL, // Note: These are hardcoded as we're not supporting AU bank accounts for the free plan @@ -150,11 +109,9 @@ class BankAccountStep extends React.Component { /** * Add the Bank account retrieved via Plaid in db */ - addPlaidAccount() { - const selectedPlaidBankAccount = this.state.selectedPlaidBankAccount; - if (!this.state.selectedPlaidBankAccount) { - return; - } + addPlaidAccount(values) { + const selectedPlaidBankAccount = values.selectedPlaidBankAccount; + BankAccounts.setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, @@ -185,8 +142,6 @@ class BankAccountStep extends React.Component { const subStep = shouldReinitializePlaidLink ? CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID : this.props.achData.subStep; const plaidDesktopMessage = getPlaidDesktopMessage(); const bankAccountRoute = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.BANK_ACCOUNT}`; - const error = lodashGet(this.props, 'reimbursementAccount.error', ''); - const loading = lodashGet(this.props, 'reimbursementAccount.loading', false); const validated = lodashGet(this.props, 'user.validated', false); return ( @@ -274,36 +229,30 @@ class BankAccountStep extends React.Component { )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( - - - { - this.setState({ - selectedPlaidBankAccount: params.selectedPlaidBankAccount, - }); - }} - onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} - receivedRedirectURI={this.props.receivedRedirectURI} - plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} - allowDebit - /> - - {!_.isUndefined(this.state.selectedPlaidBankAccount) && ( - - )} - +
+ BankAccounts.setBankAccountSubStep(null)} + receivedRedirectURI={this.props.receivedRedirectURI} + plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} + allowDebit + /> + )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( - {this.props.translate('bankAccount.checkHelpLine')} @@ -314,26 +263,21 @@ class BankAccountStep extends React.Component { source={exampleCheckImage(this.props.preferredLocale)} /> this.clearErrorAndSetValue('routingNumber', value)} disabled={shouldDisableInputs} - errorText={this.getErrorText('routingNumber')} /> this.clearErrorAndSetValue('accountNumber', value)} disabled={shouldDisableInputs} - errorText={this.getErrorText('accountNumber')} /> ( @@ -344,9 +288,8 @@ class BankAccountStep extends React.Component { )} - errorText={this.getErrorText('hasAcceptedTerms')} /> - + )}
); @@ -359,12 +302,6 @@ BankAccountStep.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ - reimbursementAccount: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, - }, - reimbursementAccountDraft: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, - }, user: { key: ONYXKEYS.USER, }, From 8808c9ce79ec429e2dfa5081abb6fd27efab5bf9 Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Wed, 7 Sep 2022 01:11:08 +0530 Subject: [PATCH 02/13] fixed console warnings & changed inputID defaultValue from undefined to null --- src/ONYXKEYS.js | 2 +- src/components/AddPlaidBankAccount.js | 2 +- src/pages/ReimbursementAccount/BankAccountStep.js | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 995a853489ec..4b36b09c79a0 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -172,6 +172,6 @@ export default { ADD_DEBIT_CARD_FORM: 'addDebitCardForm', REQUEST_CALL_FORM: 'requestCallForm', BANK_ACCOUNT_STEP_FORM_MANUAL: 'bankAccountStepFormManual', - BANK_ACCOUNT_STEP_FORM_PLAID: 'bankAccountStepFormPlaid', + BANK_ACCOUNT_STEP_FORM_PLAID: 'bankAccountStepFormPlaid', }, }; diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 642899cba2fd..567e928f4e30 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -57,7 +57,7 @@ const propTypes = { }; const defaultProps = { - inputID: undefined, + inputID: null, plaidData: { bankName: '', plaidAccessToken: '', diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 35ca433270ed..311945233679 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -64,7 +64,8 @@ class BankAccountStep extends React.Component { } /** - * @returns {Boolean} + * @param {Object} values - form input values passed by the Form component + * @returns {Object} */ validate(values) { const errors = {}; @@ -82,7 +83,6 @@ class BankAccountStep extends React.Component { return errors; } - validatePlaidAccount(values) { const errors = {}; if (_.isUndefined(values.selectedPlaidBankAccount)) { @@ -108,6 +108,7 @@ class BankAccountStep extends React.Component { /** * Add the Bank account retrieved via Plaid in db + * @param {Object} values - form input values passed by the Form component */ addPlaidAccount(values) { const selectedPlaidBankAccount = values.selectedPlaidBankAccount; From 9bf731241517920edab90e807cf34bfdecfffa58 Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Thu, 8 Sep 2022 17:19:20 +0530 Subject: [PATCH 03/13] added shouldSaveDraft to inputs and checkbox --- src/pages/ReimbursementAccount/BankAccountStep.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 311945233679..2ffb44ffb6e4 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -268,6 +268,7 @@ class BankAccountStep extends React.Component { label={this.props.translate('bankAccount.routingNumber')} keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} disabled={shouldDisableInputs} + shouldSaveDraft />
)} + shouldSaveDraft /> )} From 191739a23126f70c0c500662816fc5b5e5cee190 Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Wed, 21 Sep 2022 10:39:44 +0530 Subject: [PATCH 04/13] added isSubmitButtonVisible form prop --- src/components/Form.js | 28 +++++++++++-------- .../ReimbursementAccount/BankAccountStep.js | 26 +++++++++++------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/components/Form.js b/src/components/Form.js index f42101700862..614fd0c33f28 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -40,6 +40,9 @@ const propTypes = { // eslint-disable-next-line react/forbid-prop-types draftValues: PropTypes.object, + /** Should we show the form button */ + isSubmitButtonVisible: PropTypes.bool, + ...withLocalizePropTypes, }; @@ -49,6 +52,7 @@ const defaultProps = { error: '', }, draftValues: {}, + isSubmitButtonVisible: true, }; class Form extends React.Component { @@ -184,17 +188,19 @@ class Form extends React.Component { > {this.childrenWrapperWithProps(this.props.children)} - 0 || Boolean(this.props.formState.error)} - isLoading={this.props.formState.isLoading} - message={this.props.formState.error} - onSubmit={this.submit} - onFixTheErrorsLinkPressed={() => { - this.inputRefs[_.first(_.keys(this.state.errors))].focus(); - }} - containerStyles={[styles.mh0, styles.mt5]} - /> + {this.props.isSubmitButtonVisible && ( + 0 || Boolean(this.props.formState.error)} + isLoading={this.props.formState.isLoading} + message={this.props.formState.error} + onSubmit={this.submit} + onFixTheErrorsLinkPressed={() => { + this.inputRefs[_.first(_.keys(this.state.errors))].focus(); + }} + containerStyles={[styles.mh0, styles.mt5]} + /> + )} diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 906f75250122..27e857fcc875 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -61,6 +61,9 @@ class BankAccountStep extends React.Component { this.addPlaidAccount = this.addPlaidAccount.bind(this); this.validate = this.validate.bind(this); this.validatePlaidAccount = this.validatePlaidAccount.bind(this); + this.state = { + selectedPlaidBankAccount: undefined, + }; } /** @@ -83,9 +86,10 @@ class BankAccountStep extends React.Component { return errors; } - validatePlaidAccount(values) { + validatePlaidAccount() { + const selectedPlaidBankAccount = this.state.selectedPlaidBankAccount; const errors = {}; - if (_.isUndefined(values.selectedPlaidBankAccount)) { + if (_.isUndefined(selectedPlaidBankAccount)) { errors.selectedPlaidBankAccount = this.props.translate('bankAccount.error.noBankAccountSelected'); } @@ -110,9 +114,11 @@ class BankAccountStep extends React.Component { * Add the Bank account retrieved via Plaid in db * @param {Object} values - form input values passed by the Form component */ - addPlaidAccount(values) { - const selectedPlaidBankAccount = values.selectedPlaidBankAccount; - + addPlaidAccount() { + const selectedPlaidBankAccount = this.state.selectedPlaidBankAccount; + if (!this.state.selectedPlaidBankAccount) { + return; + } BankAccounts.setupWithdrawalAccount({ acceptTerms: true, setupType: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID, @@ -235,11 +241,15 @@ class BankAccountStep extends React.Component { validate={this.validatePlaidAccount} onSubmit={this.addPlaidAccount} submitButtonText={this.props.translate('common.saveAndContinue')} - style={[styles.mh5, styles.mb5, styles.flex1]} + style={[styles.mh5, styles.flexGrow1]} + isSubmitButtonVisible={!_.isUndefined(this.state.selectedPlaidBankAccount)} > { + this.setState({ + selectedPlaidBankAccount: params.selectedPlaidBankAccount, + }); + }} onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} receivedRedirectURI={this.props.receivedRedirectURI} plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} From 2d99e3855523935f5463c235ae72ee680abcdceb Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Fri, 23 Sep 2022 23:12:08 +0530 Subject: [PATCH 05/13] skipped validation for plaid --- src/components/Form.js | 6 +++--- src/pages/ReimbursementAccount/BankAccountStep.js | 12 ------------ 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/components/Form.js b/src/components/Form.js index 614fd0c33f28..d30043f857e6 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -16,6 +16,9 @@ const propTypes = { /** Text to be displayed in the submit button */ submitButtonText: PropTypes.string.isRequired, + /** Should we show the submit button */ + isSubmitButtonVisible: PropTypes.bool, + /** Callback to validate the form */ validate: PropTypes.func.isRequired, @@ -40,9 +43,6 @@ const propTypes = { // eslint-disable-next-line react/forbid-prop-types draftValues: PropTypes.object, - /** Should we show the form button */ - isSubmitButtonVisible: PropTypes.bool, - ...withLocalizePropTypes, }; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 27e857fcc875..a0285549a39e 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -60,7 +60,6 @@ class BankAccountStep extends React.Component { this.addManualAccount = this.addManualAccount.bind(this); this.addPlaidAccount = this.addPlaidAccount.bind(this); this.validate = this.validate.bind(this); - this.validatePlaidAccount = this.validatePlaidAccount.bind(this); this.state = { selectedPlaidBankAccount: undefined, }; @@ -86,16 +85,6 @@ class BankAccountStep extends React.Component { return errors; } - validatePlaidAccount() { - const selectedPlaidBankAccount = this.state.selectedPlaidBankAccount; - const errors = {}; - if (_.isUndefined(selectedPlaidBankAccount)) { - errors.selectedPlaidBankAccount = this.props.translate('bankAccount.error.noBankAccountSelected'); - } - - return errors; - } - addManualAccount(values) { BankAccounts.setupWithdrawalAccount({ acceptTerms: values.acceptedTerms, @@ -238,7 +227,6 @@ class BankAccountStep extends React.Component { {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && (
Date: Fri, 23 Sep 2022 23:15:18 +0530 Subject: [PATCH 06/13] removed inputID from AddPlaidBankAccount --- src/components/AddPlaidBankAccount.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index 567e928f4e30..c0f926430b0c 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -50,14 +50,10 @@ const propTypes = { /** Are we adding a withdrawal account? */ allowDebit: PropTypes.bool, - /** The ID used to uniquely identify the input in a Form */ - inputID: PropTypes.string, - ...withLocalizePropTypes, }; const defaultProps = { - inputID: null, plaidData: { bankName: '', plaidAccessToken: '', @@ -195,7 +191,6 @@ class AddPlaidBankAccount extends React.Component { Date: Sat, 24 Sep 2022 11:31:16 +0530 Subject: [PATCH 07/13] added validate function to PLAID Form --- src/pages/ReimbursementAccount/BankAccountStep.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index a0285549a39e..f31825c80fe1 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -227,6 +227,7 @@ class BankAccountStep extends React.Component { {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( ({})} onSubmit={this.addPlaidAccount} submitButtonText={this.props.translate('common.saveAndContinue')} style={[styles.mh5, styles.flexGrow1]} From 5f08c3049fb2240b023811ab8e774ae487b29f67 Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Mon, 26 Sep 2022 20:53:04 +0530 Subject: [PATCH 08/13] updated onyx key name for bankaccount form --- src/ONYXKEYS.js | 1 + src/pages/ReimbursementAccount/BankAccountStep.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index ab94c4dff47c..35be2abca7b0 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -171,5 +171,6 @@ export default { FORMS: { ADD_DEBIT_CARD_FORM: 'addDebitCardForm', REQUEST_CALL_FORM: 'requestCallForm', + BANK_FORM: 'reimbursementAccount', }, }; diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index f31825c80fe1..ca23f0e62ab3 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -226,7 +226,7 @@ class BankAccountStep extends React.Component { )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( ({})} onSubmit={this.addPlaidAccount} submitButtonText={this.props.translate('common.saveAndContinue')} @@ -248,7 +248,7 @@ class BankAccountStep extends React.Component { )} {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( Date: Tue, 27 Sep 2022 02:22:06 +0530 Subject: [PATCH 09/13] added form component to BankAccountManualStep & BankAccountPlaidStep --- .../BankAccountManualStep.js | 88 ++++++------------- .../BankAccountPlaidStep.js | 14 ++- .../ReimbursementAccount/BankAccountStep.js | 1 - 3 files changed, 40 insertions(+), 63 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js index c291af8f0a2f..41835c1a21ef 100644 --- a/src/pages/ReimbursementAccount/BankAccountManualStep.js +++ b/src/pages/ReimbursementAccount/BankAccountManualStep.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import React from 'react'; import {Image, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -15,9 +14,8 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize import * as ValidationUtils from '../../libs/ValidationUtils'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; -import * as ReimbursementAccount from '../../libs/actions/ReimbursementAccount'; import exampleCheckImage from './exampleCheckImage'; -import ReimbursementAccountForm from './ReimbursementAccountForm'; +import Form from '../../components/Form'; import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; const propTypes = { @@ -27,73 +25,42 @@ const propTypes = { class BankAccountManualStep extends React.Component { constructor(props) { super(props); - this.submit = this.submit.bind(this); - this.clearErrorAndSetValue = this.clearErrorAndSetValue.bind(this); - this.getErrorText = inputKey => ReimbursementAccountUtils.getErrorText(this.props, this.errorTranslationKeys, inputKey); - - this.state = { - acceptTerms: ReimbursementAccountUtils.getDefaultStateForField(props, 'acceptTerms', true), - routingNumber: ReimbursementAccountUtils.getDefaultStateForField(props, 'routingNumber'), - accountNumber: ReimbursementAccountUtils.getDefaultStateForField(props, 'accountNumber'), - }; - - // Map a field to the key of the error's translation - this.errorTranslationKeys = { - routingNumber: 'bankAccount.error.routingNumber', - accountNumber: 'bankAccount.error.accountNumber', - acceptTerms: 'common.error.acceptedTerms', - }; + this.validate = this.validate.bind(this); } /** - * @returns {Boolean} + * @param {Object} values - form input values passed by the Form component + * @returns {Object} */ - validate() { + validate(values) { const errorFields = {}; - const routingNumber = this.state.routingNumber.trim(); + const routingNumber = values.routingNumber && values.routingNumber.trim(); - if (!CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(this.state.accountNumber.trim())) { - errorFields.accountNumber = true; + if (!values.accountNumber || !CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim())) { + errorFields.accountNumber = this.props.translate('bankAccount.error.accountNumber'); } - if (!CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber)) { - errorFields.routingNumber = true; + if (!routingNumber || !CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber)) { + errorFields.routingNumber = this.props.translate('bankAccount.error.routingNumber'); } - if (!this.state.acceptTerms) { - errorFields.acceptTerms = true; + if (!values.acceptedTerms) { + errorFields.acceptedTerms = this.props.translate('common.error.acceptedTerms'); } - ReimbursementAccount.setBankAccountFormValidationErrors(errorFields); - - return _.size(errorFields) === 0; + return errorFields; } - submit() { - if (!this.validate()) { - return; - } - + submit(values) { const params = { bankAccountID: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID', 0), mask: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'plaidMask'), bankName: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankName'), plaidAccountID: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'plaidAccountID'), - ...this.state, + ...values, }; BankAccounts.setupWithdrawalAccount(params); } - /** - * @param {String} inputKey - * @param {String} value - */ - clearErrorAndSetValue(inputKey, value) { - const newState = {[inputKey]: value}; - this.setState(newState); - ReimbursementAccount.updateReimbursementAccountDraft(newState); - ReimbursementAccountUtils.clearError(this.props, inputKey); - } - render() { const shouldDisableInputs = Boolean(ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID')); @@ -108,7 +75,13 @@ class BankAccountManualStep extends React.Component { onBackButtonPress={() => BankAccounts.setBankAccountSubStep(null)} onCloseButtonPress={Navigation.dismissModal} /> - + {this.props.translate('bankAccount.checkHelpLine')} @@ -118,26 +91,23 @@ class BankAccountManualStep extends React.Component { source={exampleCheckImage(this.props.preferredLocale)} /> this.clearErrorAndSetValue('routingNumber', value)} disabled={shouldDisableInputs} - errorText={this.getErrorText('routingNumber')} + shouldSaveDraft /> this.clearErrorAndSetValue('accountNumber', value)} disabled={shouldDisableInputs} - errorText={this.getErrorText('accountNumber')} + shouldSaveDraft /> this.clearErrorAndSetValue('acceptTerms', value)} + inputID="acceptedTerms" LabelComponent={() => ( @@ -148,9 +118,9 @@ class BankAccountManualStep extends React.Component { )} - errorText={this.getErrorText('acceptTerms')} + shouldSaveDraft /> - + ); } diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js index f738aecf7d8d..2995db8c32b9 100644 --- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js +++ b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js @@ -11,8 +11,9 @@ import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import AddPlaidBankAccount from '../../components/AddPlaidBankAccount'; import * as ReimbursementAccount from '../../libs/actions/ReimbursementAccount'; -import ReimbursementAccountForm from './ReimbursementAccountForm'; import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; +import Form from '../../components/Form'; +import styles from '../../styles/styles'; const propTypes = { /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ @@ -69,7 +70,14 @@ class BankAccountPlaidStep extends React.Component { onBackButtonPress={() => BankAccounts.setBankAccountSubStep(null)} onCloseButtonPress={Navigation.dismissModal} /> - +
({})} + onSubmit={this.submit} + submitButtonText={this.props.translate('common.saveAndContinue')} + style={[styles.mh5, styles.flexGrow1]} + isSubmitButtonVisible={!_.isUndefined(this.props.plaidData.selectedPlaidBankAccount)} + > { @@ -81,7 +89,7 @@ class BankAccountPlaidStep extends React.Component { allowDebit bankAccountID={bankAccountID} /> - + ); } diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index a35b1bac8729..c2f64a4e22a5 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -24,7 +24,6 @@ import getPlaidDesktopMessage from '../../libs/getPlaidDesktopMessage'; import CONFIG from '../../CONFIG'; import ROUTES from '../../ROUTES'; import Button from '../../components/Button'; -import Form from '../../components/Form'; const propTypes = { /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ From e19f42f527920701c92a0402846393ab7254b24c Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Tue, 27 Sep 2022 02:23:08 +0530 Subject: [PATCH 10/13] updated formID for plaid --- src/pages/ReimbursementAccount/BankAccountPlaidStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js index 2995db8c32b9..b4ebb7ce136c 100644 --- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js +++ b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js @@ -71,7 +71,7 @@ class BankAccountPlaidStep extends React.Component { onCloseButtonPress={Navigation.dismissModal} />
({})} onSubmit={this.submit} submitButtonText={this.props.translate('common.saveAndContinue')} From 27dddb3c3358427b01d43b6c9f85d636ae37671d Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Wed, 28 Sep 2022 23:41:02 +0530 Subject: [PATCH 11/13] updated ONYX key name from BANK_FORM to REIMBURSEMENT_ACCOUNT_FORM --- src/ONYXKEYS.js | 2 +- src/pages/ReimbursementAccount/BankAccountManualStep.js | 2 +- src/pages/ReimbursementAccount/BankAccountPlaidStep.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 35be2abca7b0..fb182641fa0c 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -171,6 +171,6 @@ export default { FORMS: { ADD_DEBIT_CARD_FORM: 'addDebitCardForm', REQUEST_CALL_FORM: 'requestCallForm', - BANK_FORM: 'reimbursementAccount', + REIMBURSEMENT_ACCOUNT_FORM: 'reimbursementAccount', }, }; diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js index 84fc0e3665c6..afaa3b1c7851 100644 --- a/src/pages/ReimbursementAccount/BankAccountManualStep.js +++ b/src/pages/ReimbursementAccount/BankAccountManualStep.js @@ -74,7 +74,7 @@ class BankAccountManualStep extends React.Component { onCloseButtonPress={Navigation.dismissModal} /> ({})} onSubmit={this.submit} submitButtonText={this.props.translate('common.saveAndContinue')} From bd2e691375b7c92e246e11d549041b1caca7de64 Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Sat, 1 Oct 2022 00:27:13 +0530 Subject: [PATCH 12/13] merged code from Form and FormActions --- src/components/Form.js | 42 +++++++++++++++++++-------------- src/libs/actions/FormActions.js | 10 ++++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/components/Form.js b/src/components/Form.js index d30043f857e6..346c6023b5cd 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx'; import compose from '../libs/compose'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import * as FormActions from '../libs/actions/FormActions'; +import * as ErrorUtils from '../libs/ErrorUtils'; import styles from '../styles/styles'; import FormAlertWithSubmitButton from './FormAlertWithSubmitButton'; @@ -16,7 +17,7 @@ const propTypes = { /** Text to be displayed in the submit button */ submitButtonText: PropTypes.string.isRequired, - /** Should we show the submit button */ + /** Controls the submit button's visibility */ isSubmitButtonVisible: PropTypes.bool, /** Callback to validate the form */ @@ -35,8 +36,8 @@ const propTypes = { /** Controls the loading state of the form */ isLoading: PropTypes.bool, - /** Server side error message */ - error: PropTypes.string, + /** Server side errors keyed by microtime */ + errors: PropTypes.objectOf(PropTypes.string), }), /** Contains draft values for each input in the form */ @@ -47,12 +48,12 @@ const propTypes = { }; const defaultProps = { + isSubmitButtonVisible: true, formState: { isLoading: false, - error: '', + errors: null, }, draftValues: {}, - isSubmitButtonVisible: true, }; class Form extends React.Component { @@ -79,6 +80,11 @@ class Form extends React.Component { this.touchedInputs[inputID] = true; } + getErrorMessage() { + const latestErrorMessage = ErrorUtils.getLatestErrorMessage(this.props.formState); + return this.props.formState.error || (typeof latestErrorMessage === 'string' ? latestErrorMessage : ''); + } + submit() { // Return early if the form is already submitting to avoid duplicate submission if (this.props.formState.isLoading) { @@ -104,7 +110,7 @@ class Form extends React.Component { * @returns {Object} - An object containing the errors for each inputID, e.g. {inputID1: error1, inputID2: error2} */ validate(values) { - FormActions.setErrorMessage(this.props.formID, ''); + FormActions.setErrors(this.props.formID, null); const validationErrors = this.props.validate(values); if (!_.isObject(validationErrors)) { @@ -189,17 +195,17 @@ class Form extends React.Component { {this.childrenWrapperWithProps(this.props.children)} {this.props.isSubmitButtonVisible && ( - 0 || Boolean(this.props.formState.error)} - isLoading={this.props.formState.isLoading} - message={this.props.formState.error} - onSubmit={this.submit} - onFixTheErrorsLinkPressed={() => { - this.inputRefs[_.first(_.keys(this.state.errors))].focus(); - }} - containerStyles={[styles.mh0, styles.mt5]} - /> + 0 || Boolean(this.getErrorMessage())} + isLoading={this.props.formState.isLoading} + message={this.getErrorMessage()} + onSubmit={this.submit} + onFixTheErrorsLinkPressed={() => { + this.inputRefs[_.first(_.keys(this.state.errors))].focus(); + }} + containerStyles={[styles.mh0, styles.mt5]} + /> )} @@ -221,4 +227,4 @@ export default compose( key: props => `${props.formID}DraftValues`, }, }), -)(Form); +)(Form); \ No newline at end of file diff --git a/src/libs/actions/FormActions.js b/src/libs/actions/FormActions.js index eb087e673361..2347158c3144 100644 --- a/src/libs/actions/FormActions.js +++ b/src/libs/actions/FormActions.js @@ -10,10 +10,10 @@ function setIsLoading(formID, isLoading) { /** * @param {String} formID - * @param {String} error + * @param {String} errors */ -function setErrorMessage(formID, error) { - Onyx.merge(formID, {error}); +function setErrors(formID, errors) { + Onyx.merge(formID, {errors}); } /** @@ -26,6 +26,6 @@ function setDraftValues(formID, draftValues) { export { setIsLoading, - setErrorMessage, + setErrors, setDraftValues, -}; +}; \ No newline at end of file From 08753f35b296b220ce0f3393fa2b8dceef177e0e Mon Sep 17 00:00:00 2001 From: jayeshmangwani Date: Sat, 1 Oct 2022 00:43:38 +0530 Subject: [PATCH 13/13] fixed newline lint issue --- src/components/Form.js | 2 +- src/libs/actions/FormActions.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Form.js b/src/components/Form.js index 346c6023b5cd..4e084cfb6209 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -227,4 +227,4 @@ export default compose( key: props => `${props.formID}DraftValues`, }, }), -)(Form); \ No newline at end of file +)(Form); diff --git a/src/libs/actions/FormActions.js b/src/libs/actions/FormActions.js index 2347158c3144..188d10b759b7 100644 --- a/src/libs/actions/FormActions.js +++ b/src/libs/actions/FormActions.js @@ -28,4 +28,4 @@ export { setIsLoading, setErrors, setDraftValues, -}; \ No newline at end of file +};