-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Form refactor bankaccountstep #10900
Changes from 8 commits
c09bf34
3f8c116
8808c9c
9bf7312
7ecc6c2
590d0df
f4134db
191739a
90057a2
2d99e38
cdb883a
2ef74ca
0e2b26f
4bdc2d7
5f08c30
df9b2c0
84011f1
e19f42f
e8c0496
58198e2
27dddb3
ebcc540
44cc59d
fbd3ca4
bd2e691
08753f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,24 +22,16 @@ import Text from '../../components/Text'; | |
import * as BankAccounts from '../../libs/actions/BankAccounts'; | ||
import ONYXKEYS from '../../ONYXKEYS'; | ||
import compose from '../../libs/compose'; | ||
import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; | ||
import ReimbursementAccountForm from './ReimbursementAccountForm'; | ||
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; | ||
import Section from '../../components/Section'; | ||
import * as ValidationUtils from '../../libs/ValidationUtils'; | ||
import * as Illustrations from '../../components/Icon/Illustrations'; | ||
import getPlaidDesktopMessage from '../../libs/getPlaidDesktopMessage'; | ||
import CONFIG from '../../CONFIG'; | ||
import ROUTES from '../../ROUTES'; | ||
import Button from '../../components/Button'; | ||
import FormScrollView from '../../components/FormScrollView'; | ||
import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton'; | ||
import Form from '../../components/Form'; | ||
|
||
const propTypes = { | ||
/** Bank account currently in setup */ | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
reimbursementAccount: reimbursementAccountPropTypes.isRequired, | ||
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ | ||
receivedRedirectURI: PropTypes.string, | ||
|
||
|
@@ -65,79 +57,50 @@ class BankAccountStep extends React.Component { | |
constructor(props) { | ||
super(props); | ||
|
||
this.toggleTerms = this.toggleTerms.bind(this); | ||
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, | ||
hasAcceptedTerms: ReimbursementAccountUtils.getDefaultStateForField(props, 'acceptTerms', true), | ||
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
routingNumber: ReimbursementAccountUtils.getDefaultStateForField(props, 'routingNumber'), | ||
accountNumber: ReimbursementAccountUtils.getDefaultStateForField(props, 'accountNumber'), | ||
}; | ||
|
||
// Keys in this.errorTranslationKeys are associated to inputs, they are a subset of the keys found in this.state | ||
this.errorTranslationKeys = { | ||
routingNumber: 'bankAccount.error.routingNumber', | ||
accountNumber: 'bankAccount.error.accountNumber', | ||
hasAcceptedTerms: 'common.error.acceptedTerms', | ||
}; | ||
|
||
this.getErrorText = inputKey => 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'); | ||
} | ||
|
||
/** | ||
* @returns {Boolean} | ||
* @param {Object} values - form input values passed by the Form component | ||
* @returns {Object} | ||
*/ | ||
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; | ||
} | ||
|
||
/** | ||
* 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); | ||
return errors; | ||
} | ||
|
||
addManualAccount() { | ||
if (!this.validate()) { | ||
return; | ||
validatePlaidAccount() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can skip validating Plaid account, as we don't allow the user to continue unless they choose an account. I don't see a way of triggering the validation error if it exists. @luacmartins what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I think we can skip this, removed validatePlaidAccount for now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense since we can't display that error and the user can't continue without selecting an account. |
||
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: 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 | ||
|
@@ -149,6 +112,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() { | ||
const selectedPlaidBankAccount = this.state.selectedPlaidBankAccount; | ||
|
@@ -185,8 +149,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 ( | ||
<View style={[styles.flex1, styles.justifyContentBetween]}> | ||
|
@@ -274,36 +236,34 @@ class BankAccountStep extends React.Component { | |
</ScrollView> | ||
)} | ||
{subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( | ||
<FormScrollView> | ||
<View style={[styles.mh5, styles.mb5, styles.flex1]}> | ||
<AddPlaidBankAccount | ||
text={this.props.translate('bankAccount.plaidBodyCopy')} | ||
onSelect={(params) => { | ||
this.setState({ | ||
selectedPlaidBankAccount: params.selectedPlaidBankAccount, | ||
}); | ||
}} | ||
onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} | ||
receivedRedirectURI={this.props.receivedRedirectURI} | ||
plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} | ||
allowDebit | ||
/> | ||
</View> | ||
{!_.isUndefined(this.state.selectedPlaidBankAccount) && ( | ||
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<FormAlertWithSubmitButton | ||
isAlertVisible={Boolean(error)} | ||
buttonText={this.props.translate('common.saveAndContinue')} | ||
onSubmit={this.addPlaidAccount} | ||
message={error} | ||
isLoading={loading} | ||
/> | ||
)} | ||
</FormScrollView> | ||
<Form | ||
formID={ONYXKEYS.REIMBURSEMENT_ACCOUNT} | ||
validate={this.validatePlaidAccount} | ||
onSubmit={this.addPlaidAccount} | ||
submitButtonText={this.props.translate('common.saveAndContinue')} | ||
style={[styles.mh5, styles.flexGrow1]} | ||
isSubmitButtonVisible={!_.isUndefined(this.state.selectedPlaidBankAccount)} | ||
> | ||
<AddPlaidBankAccount | ||
onSelect={(params) => { | ||
this.setState({ | ||
selectedPlaidBankAccount: params.selectedPlaidBankAccount, | ||
}); | ||
}} | ||
onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} | ||
receivedRedirectURI={this.props.receivedRedirectURI} | ||
plaidLinkOAuthToken={this.props.plaidLinkOAuthToken} | ||
allowDebit | ||
/> | ||
</Form> | ||
)} | ||
{subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( | ||
<ReimbursementAccountForm | ||
reimbursementAccount={this.props.reimbursementAccount} | ||
<Form | ||
formID={ONYXKEYS.REIMBURSEMENT_ACCOUNT} | ||
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
validate={this.validate} | ||
onSubmit={this.addManualAccount} | ||
submitButtonText={this.props.translate('common.saveAndContinue')} | ||
style={[styles.mh5, styles.flexGrow1]} | ||
> | ||
<Text style={[styles.mb5]}> | ||
{this.props.translate('bankAccount.checkHelpLine')} | ||
|
@@ -314,26 +274,23 @@ class BankAccountStep extends React.Component { | |
source={exampleCheckImage(this.props.preferredLocale)} | ||
/> | ||
<TextInput | ||
inputID="routingNumber" | ||
label={this.props.translate('bankAccount.routingNumber')} | ||
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} | ||
value={this.state.routingNumber} | ||
onChangeText={value => this.clearErrorAndSetValue('routingNumber', value)} | ||
disabled={shouldDisableInputs} | ||
errorText={this.getErrorText('routingNumber')} | ||
shouldSaveDraft | ||
/> | ||
<TextInput | ||
inputID="accountNumber" | ||
containerStyles={[styles.mt4]} | ||
label={this.props.translate('bankAccount.accountNumber')} | ||
keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} | ||
value={this.state.accountNumber} | ||
onChangeText={value => this.clearErrorAndSetValue('accountNumber', value)} | ||
disabled={shouldDisableInputs} | ||
errorText={this.getErrorText('accountNumber')} | ||
shouldSaveDraft | ||
/> | ||
<CheckboxWithLabel | ||
style={styles.mt4} | ||
isChecked={this.state.hasAcceptedTerms} | ||
onInputChange={this.toggleTerms} | ||
inputID="acceptedTerms" | ||
LabelComponent={() => ( | ||
<View style={[styles.flexRow, styles.alignItemsCenter]}> | ||
<Text> | ||
|
@@ -344,9 +301,9 @@ class BankAccountStep extends React.Component { | |
</TextLink> | ||
</View> | ||
)} | ||
errorText={this.getErrorText('hasAcceptedTerms')} | ||
shouldSaveDraft | ||
/> | ||
</ReimbursementAccountForm> | ||
</Form> | ||
)} | ||
</View> | ||
); | ||
|
@@ -359,12 +316,6 @@ BankAccountStep.defaultProps = defaultProps; | |
export default compose( | ||
withLocalize, | ||
withOnyx({ | ||
reimbursementAccount: { | ||
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, | ||
}, | ||
reimbursementAccountDraft: { | ||
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, | ||
}, | ||
user: { | ||
key: ONYXKEYS.USER, | ||
}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be moved below
submitButtonText
, as now it sits under the/* Onyx Props */
comment but it's not an Onyx prop.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change has been done