From 0c095688f307f8e285626ae117fd854a3cde4e68 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:01:59 +0700 Subject: [PATCH 01/13] adding hint text for zip code format --- src/languages/en.js | 1 + src/languages/es.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index be1b3b612d22..cda807f1aec4 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -108,6 +108,7 @@ export default { maxParticipantsReached: ({count}) => `You've selected the maximum number (${count}) of participants.`, youAppearToBeOffline: 'You appear to be offline.', thisFeatureRequiresInternet: 'This feature requires an active internet connection to be used.', + zipCodeExample: 'e.x 12345, 12345-1234, 12345 1234', }, attachmentPicker: { cameraPermissionRequired: 'Camera permission required', diff --git a/src/languages/es.js b/src/languages/es.js index ffd4fb06748e..3f009b11e4e6 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -108,6 +108,7 @@ export default { maxParticipantsReached: ({count}) => `Has seleccionado el número máximo (${count}) de participantes.`, youAppearToBeOffline: 'Parece que estás desconectado.', thisFeatureRequiresInternet: 'Esta función requiere una conexión a Internet activa para ser utilizada.', + zipCodeExample: 'e.x 12345, 12345-1234, 12345 1234', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', From bd8c2240439c8f2785de0c994e3bd8d737f6e112 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:02:22 +0700 Subject: [PATCH 02/13] adding defaultValues props to handle default value inputs --- src/pages/ReimbursementAccount/AddressForm.js | 26 ++++++++++ .../ReimbursementAccount/IdentityForm.js | 49 +++++++++++++++++-- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/pages/ReimbursementAccount/AddressForm.js b/src/pages/ReimbursementAccount/AddressForm.js index 9e734a70d403..71704fd04e58 100644 --- a/src/pages/ReimbursementAccount/AddressForm.js +++ b/src/pages/ReimbursementAccount/AddressForm.js @@ -15,6 +15,21 @@ const propTypes = { /** Callback fired when a field changes. Passes args as {[fieldName]: val} */ onFieldChange: PropTypes.func, + /** Default values */ + defaultValues: PropTypes.shape({ + /** Address street field */ + street: PropTypes.string, + + /** Address city field */ + city: PropTypes.string, + + /** Address state field */ + state: PropTypes.string, + + /** Address zip code field */ + zipCode: PropTypes.string, + }), + /** Form values */ values: PropTypes.shape({ /** Address street field */ @@ -55,6 +70,12 @@ const defaultProps = { state: undefined, zipCode: undefined, }, + defaultValues: { + street: undefined, + city: undefined, + state: undefined, + zipCode: undefined, + }, errors: {}, inputKeys: { street: '', @@ -75,6 +96,7 @@ const AddressForm = props => ( label={props.translate(props.streetTranslationKey)} containerStyles={[styles.mt4]} value={props.values.street} + defaultValue={props.defaultValues.street} onInputChange={props.onFieldChange} errorText={props.errors.street ? props.translate('bankAccount.error.addressStreet') : ''} hint={props.translate('common.noPO')} @@ -88,6 +110,7 @@ const AddressForm = props => ( shouldSaveDraft={props.shouldSaveDraft} label={props.translate('common.city')} value={props.values.city} + defaultValue={props.defaultValues.city} onChangeText={value => props.onFieldChange({city: value})} errorText={props.errors.city ? props.translate('bankAccount.error.addressCity') : ''} /> @@ -97,6 +120,7 @@ const AddressForm = props => ( inputID={props.inputKeys.state} shouldSaveDraft={props.shouldSaveDraft} value={props.values.state} + defaultValue={props.defaultValues.street} onInputChange={value => props.onFieldChange({state: value})} errorText={props.errors.state ? props.translate('bankAccount.error.addressState') : ''} /> @@ -109,9 +133,11 @@ const AddressForm = props => ( containerStyles={[styles.mt4]} keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} value={props.values.zipCode} + defaultValue={props.defaultValues.zipCode} onChangeText={value => props.onFieldChange({zipCode: value})} errorText={props.errors.zipCode ? props.translate('bankAccount.error.zipCode') : ''} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.ZIP_CODE} + hint={props.translate('common.zipCodeExample')} /> ); diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 1c06061a44cb..95994b73d7f8 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -42,6 +42,33 @@ const propTypes = { ssnLast4: PropTypes.string, }), + /** Default values */ + defaultValues: PropTypes.shape({ + /** First name field */ + firstName: PropTypes.string, + + /** Last name field */ + lastName: PropTypes.string, + + /** Address street field */ + street: PropTypes.string, + + /** Address city field */ + city: PropTypes.string, + + /** Address state field */ + state: PropTypes.string, + + /** Address zip code field */ + zipCode: PropTypes.string, + + /** Date of birth field */ + dob: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]), + + /** Last 4 digits of SSN */ + ssnLast4: PropTypes.string, + }), + /** Any errors that can arise from form validation */ errors: PropTypes.objectOf(PropTypes.bool), @@ -76,6 +103,16 @@ const defaultProps = { dob: undefined, ssnLast4: undefined, }, + defaultValues: { + firstName: undefined, + lastName: undefined, + street: undefined, + city: undefined, + state: undefined, + zipCode: undefined, + dob: undefined, + ssnLast4: undefined, + }, errors: {}, inputKeys: { firstName: '', @@ -95,6 +132,7 @@ const IdentityForm = (props) => { // dob field has multiple validations/errors, we are handling it temporarily like this. const dobErrorText = (props.errors.dob ? props.translate('bankAccount.error.dob') : '') || (props.errors.dobAge ? props.translate('bankAccount.error.age') : ''); + const identityFormInputKeys = ['firstName', 'lastName', 'dob', 'ssnLast4']; return ( @@ -105,6 +143,7 @@ const IdentityForm = (props) => { shouldSaveDraft={props.shouldSaveDraft} label={`${props.translate('common.firstName')}`} value={props.values.firstName} + defaultValue={props.defaultValues.firstName} onChangeText={value => props.onFieldChange({firstName: value})} errorText={props.errors.firstName ? props.translate('bankAccount.error.firstName') : ''} /> @@ -115,6 +154,7 @@ const IdentityForm = (props) => { shouldSaveDraft={props.shouldSaveDraft} label={`${props.translate('common.lastName')}`} value={props.values.lastName} + defaultValue={props.defaultValues.lastName} onChangeText={value => props.onFieldChange({lastName: value})} errorText={props.errors.lastName ? props.translate('bankAccount.error.lastName') : ''} /> @@ -126,7 +166,7 @@ const IdentityForm = (props) => { label={`${props.translate('common.dob')}`} containerStyles={[styles.mt4]} placeholder={props.translate('common.dateFormat')} - defaultValue={props.values.dob} + defaultValue={props.values.dob || props.defaultValues.dob} onInputChange={value => props.onFieldChange({dob: value})} errorText={dobErrorText} maximumDate={new Date()} @@ -137,17 +177,18 @@ const IdentityForm = (props) => { label={`${props.translate('common.ssnLast4')}`} containerStyles={[styles.mt4]} keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - value={props.values.ssnLast4} + defaultValue={props.defaultValues.ssnLast4} onChangeText={value => props.onFieldChange({ssnLast4: value})} errorText={props.errors.ssnLast4 ? props.translate('bankAccount.error.ssnLast4') : ''} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.SSN} /> From d070fb29940fe110b3aed5892ff0640d772fa58a Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:02:55 +0700 Subject: [PATCH 03/13] refactoring requestor step form to use Form.js --- .../ReimbursementAccount/RequestorStep.js | 210 +++++++----------- 1 file changed, 81 insertions(+), 129 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 05fc624d61be..ef0bbef24090 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -2,7 +2,6 @@ import React from 'react'; import lodashGet from 'lodash/get'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import moment from 'moment'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; @@ -20,18 +19,14 @@ import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; -import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes'; -import ReimbursementAccountForm from './ReimbursementAccountForm'; import * as Link from '../../libs/actions/Link'; import RequestorOnfidoStep from './RequestorOnfidoStep'; +import Form from '../../components/Form'; const propTypes = { /** The bank account currently in setup */ - reimbursementAccount: reimbursementAccountPropTypes.isRequired, - /** The draft values of the bank account being setup */ - /* eslint-disable-next-line react/no-unused-prop-types */ - reimbursementAccountDraft: reimbursementAccountDraftPropTypes.isRequired, + reimbursementAccount: reimbursementAccountPropTypes.isRequired, /** The token required to initialize the Onfido SDK */ onfidoToken: PropTypes.string, @@ -47,38 +42,13 @@ class RequestorStep extends React.Component { constructor(props) { super(props); + this.validate = this.validate.bind(this); this.submit = this.submit.bind(this); - this.clearErrorsAndSetValues = this.clearErrorsAndSetValues.bind(this); this.setOnfidoAsComplete = this.setOnfidoAsComplete.bind(this); this.state = { - firstName: ReimbursementAccountUtils.getDefaultStateForField(props, 'firstName'), - lastName: ReimbursementAccountUtils.getDefaultStateForField(props, 'lastName'), - requestorAddressStreet: ReimbursementAccountUtils.getDefaultStateForField(props, 'requestorAddressStreet'), - requestorAddressCity: ReimbursementAccountUtils.getDefaultStateForField(props, 'requestorAddressCity'), - requestorAddressState: ReimbursementAccountUtils.getDefaultStateForField(props, 'requestorAddressState'), - requestorAddressZipCode: ReimbursementAccountUtils.getDefaultStateForField(props, 'requestorAddressZipCode'), - dob: ReimbursementAccountUtils.getDefaultStateForField(props, 'dob'), - ssnLast4: ReimbursementAccountUtils.getDefaultStateForField(props, 'ssnLast4'), - isControllingOfficer: ReimbursementAccountUtils.getDefaultStateForField(props, 'isControllingOfficer', false), isOnfidoSetupComplete: lodashGet(props, ['achData', 'isOnfidoSetupComplete'], false), }; - - // Required fields not validated by `validateIdentity` - this.requiredFields = [ - 'isControllingOfficer', - ]; - - // Map a field to the key of the error's translation - this.errorTranslationKeys = { - firstName: 'bankAccount.error.firstName', - lastName: 'bankAccount.error.lastName', - isControllingOfficer: 'requestorStep.isControllingOfficerError', - }; - - this.clearError = inputKey => ReimbursementAccountUtils.clearError(this.props, inputKey); - this.clearErrors = inputKeys => ReimbursementAccountUtils.clearErrors(this.props, inputKeys); - this.getErrors = () => ReimbursementAccountUtils.getErrors(this.props); } /** @@ -89,73 +59,64 @@ class RequestorStep extends React.Component { } /** - * Clear the errors associated to keys in values if found and store the new values in the state. - * * @param {Object} values + * @returns {Object} */ - clearErrorsAndSetValues(values) { - const renamedFields = { - street: 'requestorAddressStreet', - city: 'requestorAddressCity', - state: 'requestorAddressState', - zipCode: 'requestorAddressZipCode', - }; - const newState = {}; - _.each(values, (value, inputKey) => { - const renamedInputKey = lodashGet(renamedFields, inputKey, inputKey); - newState[renamedInputKey] = value; - }); - this.setState(newState); - BankAccounts.updateReimbursementAccountDraft(newState); + validate(values) { + const errors = {}; - // Prepare inputKeys for clearing errors - const inputKeys = _.keys(values); + if (!values.firstName) { + errors.firstName = this.props.translate('bankAccount.error.firstName'); + } - // dob field has multiple validations/errors, we are handling it temporarily like this. - if (_.contains(inputKeys, 'dob')) { - inputKeys.push('dobAge'); + if (!values.lastName) { + errors.lastName = this.props.translate('bankAccount.error.lastName'); } - this.clearErrors(inputKeys); - } - /** - * @returns {Boolean} - */ - validate() { - const errors = ValidationUtils.validateIdentity({ - firstName: this.state.firstName, - lastName: this.state.lastName, - street: this.state.requestorAddressStreet, - state: this.state.requestorAddressState, - city: this.state.requestorAddressCity, - zipCode: this.state.requestorAddressZipCode, - dob: this.state.dob, - ssnLast4: this.state.ssnLast4, - }); + if (!values.requestorAddressStreet) { + errors.requestorAddressStreet = this.props.translate('bankAccount.error.address'); + } - _.each(this.requiredFields, (inputKey) => { - if (ValidationUtils.isRequiredFulfilled(this.state[inputKey])) { - return; - } + if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) { + errors.requestorAddressStreet = this.props.translate('bankAccount.error.addressStreet'); + } - errors[inputKey] = true; - }); - if (_.size(errors)) { - BankAccounts.setBankAccountFormValidationErrors(errors); - return false; + if (!values.requestorAddressCity) { + errors.requestorAddressCity = this.props.translate('bankAccount.error.addressCity'); + } + + if (!values.requestorAddressState) { + errors.requestorAddressState = this.props.translate('bankAccount.error.addressState'); + } + + if (!values.requestorAddressZipCode || !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { + errors.requestorAddressZipCode = this.props.translate('bankAccount.error.zipCode'); + } + + if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { + errors.dob = this.props.translate('bankAccount.error.dob'); } - return true; - } - submit() { - if (!this.validate()) { - return; + if (values.dob && !ValidationUtils.meetsAgeRequirements(values.dob)) { + errors.dob = this.props.translate('bankAccount.error.age'); } + if (!values.ssnLast4 || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { + errors.ssnLast4 = this.props.translate('bankAccount.error.ssnLast4'); + } + + if (!values.isControllingOfficer) { + errors.isControllingOfficer = this.props.translate('requestorStep.isControllingOfficerError'); + } + + return errors; + } + + submit(values) { const payload = { bankAccountID: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID', 0), - ...this.state, - dob: moment(this.state.dob).format(CONST.DATE.MOMENT_FORMAT_STRING), + ...values, + dob: moment(values.dob).format(CONST.DATE.MOMENT_FORMAT_STRING), }; BankAccounts.updatePersonalInformationForBankAccount(payload); @@ -183,12 +144,14 @@ class RequestorStep extends React.Component { onCloseButtonPress={Navigation.dismissModal} /> {shouldShowOnfido ? ( - + ) : ( - {this.props.translate('requestorStep.subtitle')} @@ -209,39 +172,39 @@ class RequestorStep extends React.Component { { - this.setState((prevState) => { - const newState = {isControllingOfficer: !prevState.isControllingOfficer}; - BankAccounts.updateReimbursementAccountDraft(newState); - return newState; - }); - this.clearError('isControllingOfficer'); - }} + inputID="isControllingOfficer" + defaultValue={ReimbursementAccountUtils.getDefaultStateForField(this.props, 'isControllingOfficer', false)} LabelComponent={() => ( - - {this.props.translate('requestorStep.isControllingOfficer')} - + {this.props.translate('requestorStep.isControllingOfficer')} )} style={[styles.mt4]} - errorText={this.getErrors().isControllingOfficer ? this.props.translate('requestorStep.isControllingOfficerError') : ''} + shouldSaveDraft /> {this.props.translate('requestorStep.onFidoConditions')} @@ -253,23 +216,15 @@ class RequestorStep extends React.Component { {`${this.props.translate('onfidoStep.facialScan')}`} {', '} - Link.openExternalLink('https://onfido.com/privacy/')} - style={[styles.textMicro, styles.link]} - accessibilityRole="link" - > + Link.openExternalLink('https://onfido.com/privacy/')} style={[styles.textMicro, styles.link]} accessibilityRole="link"> {`${this.props.translate('common.privacyPolicy')}`} {` ${this.props.translate('common.and')} `} - Link.openExternalLink('https://onfido.com/terms-of-service/')} - style={[styles.textMicro, styles.link]} - accessibilityRole="link" - > + Link.openExternalLink('https://onfido.com/terms-of-service/')} style={[styles.textMicro, styles.link]} accessibilityRole="link"> {`${this.props.translate('common.termsOfService')}`} - + )} ); @@ -288,8 +243,5 @@ export default compose( onfidoToken: { key: ONYXKEYS.ONFIDO_TOKEN, }, - reimbursementAccountDraft: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, - }, }), )(RequestorStep); From bbc9f644528d8f2d06401d2a8b09ea000b68642a Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:05:51 +0700 Subject: [PATCH 04/13] reorder the inputs validation --- .../ReimbursementAccount/RequestorStep.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index ef0bbef24090..f8c0bdf92ed2 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -73,6 +73,18 @@ class RequestorStep extends React.Component { errors.lastName = this.props.translate('bankAccount.error.lastName'); } + if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { + errors.dob = this.props.translate('bankAccount.error.dob'); + } + + if (values.dob && !ValidationUtils.meetsAgeRequirements(values.dob)) { + errors.dob = this.props.translate('bankAccount.error.age'); + } + + if (!values.ssnLast4 || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { + errors.ssnLast4 = this.props.translate('bankAccount.error.ssnLast4'); + } + if (!values.requestorAddressStreet) { errors.requestorAddressStreet = this.props.translate('bankAccount.error.address'); } @@ -93,18 +105,6 @@ class RequestorStep extends React.Component { errors.requestorAddressZipCode = this.props.translate('bankAccount.error.zipCode'); } - if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { - errors.dob = this.props.translate('bankAccount.error.dob'); - } - - if (values.dob && !ValidationUtils.meetsAgeRequirements(values.dob)) { - errors.dob = this.props.translate('bankAccount.error.age'); - } - - if (!values.ssnLast4 || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { - errors.ssnLast4 = this.props.translate('bankAccount.error.ssnLast4'); - } - if (!values.isControllingOfficer) { errors.isControllingOfficer = this.props.translate('requestorStep.isControllingOfficerError'); } From 093c8cb737a1093d2c1f0f3223ce689ad5121949 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:32:29 +0700 Subject: [PATCH 05/13] fix wrong key for default value input state --- src/pages/ReimbursementAccount/AddressForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/AddressForm.js b/src/pages/ReimbursementAccount/AddressForm.js index 71704fd04e58..bccf706a16d9 100644 --- a/src/pages/ReimbursementAccount/AddressForm.js +++ b/src/pages/ReimbursementAccount/AddressForm.js @@ -120,7 +120,7 @@ const AddressForm = props => ( inputID={props.inputKeys.state} shouldSaveDraft={props.shouldSaveDraft} value={props.values.state} - defaultValue={props.defaultValues.street} + defaultValue={props.defaultValues.state} onInputChange={value => props.onFieldChange({state: value})} errorText={props.errors.state ? props.translate('bankAccount.error.addressState') : ''} /> From 514ca34d3f44174903307f655eb1041f68423e41 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 16 Nov 2022 19:33:43 +0700 Subject: [PATCH 06/13] default value fallback from achData --- .../ReimbursementAccount/RequestorStep.js | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index f8c0bdf92ed2..c615d9cc61c7 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -42,6 +42,7 @@ class RequestorStep extends React.Component { constructor(props) { super(props); + this.getDefaultStateForField = this.getDefaultStateForField.bind(this); this.validate = this.validate.bind(this); this.submit = this.submit.bind(this); this.setOnfidoAsComplete = this.setOnfidoAsComplete.bind(this); @@ -58,6 +59,16 @@ class RequestorStep extends React.Component { this.setState({isOnfidoSetupComplete: true}); } + /** + * Get default value from reimbursementAccount or achData + * @param {String} fieldName + * @param {*} defaultValue + * @returns {String} + */ + getDefaultStateForField(fieldName, defaultValue) { + return lodashGet(this.props, ['reimbursementAccount', 'achData', fieldName], defaultValue); + } + /** * @param {Object} values * @returns {Object} @@ -174,14 +185,14 @@ class RequestorStep extends React.Component { ( {this.props.translate('requestorStep.isControllingOfficer')} From 3599d9f496079492acad1e652ae0b3c936897c5c Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Thu, 17 Nov 2022 01:57:32 +0700 Subject: [PATCH 07/13] use the get default state instead --- src/pages/ReimbursementAccount/RequestorStep.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index c615d9cc61c7..e20143d2ee2d 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -17,7 +17,6 @@ import IdentityForm from './IdentityForm'; import * as ValidationUtils from '../../libs/ValidationUtils'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; -import * as ReimbursementAccountUtils from '../../libs/ReimbursementAccountUtils'; import reimbursementAccountPropTypes from './reimbursementAccountPropTypes'; import * as Link from '../../libs/actions/Link'; import RequestorOnfidoStep from './RequestorOnfidoStep'; @@ -125,7 +124,7 @@ class RequestorStep extends React.Component { submit(values) { const payload = { - bankAccountID: ReimbursementAccountUtils.getDefaultStateForField(this.props, 'bankAccountID', 0), + bankAccountID: this.getDefaultStateForField(this.props, 'bankAccountID', 0), ...values, dob: moment(values.dob).format(CONST.DATE.MOMENT_FORMAT_STRING), }; From 3bbce7b9f8c06bc234d22b3b9454229165f39e4f Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Thu, 17 Nov 2022 02:04:47 +0700 Subject: [PATCH 08/13] fix the false bankAccountID value --- src/pages/ReimbursementAccount/RequestorStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index e20143d2ee2d..43bd09a13617 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -124,7 +124,7 @@ class RequestorStep extends React.Component { submit(values) { const payload = { - bankAccountID: this.getDefaultStateForField(this.props, 'bankAccountID', 0), + bankAccountID: this.getDefaultStateForField('bankAccountID', 0), ...values, dob: moment(values.dob).format(CONST.DATE.MOMENT_FORMAT_STRING), }; From 31bbca5e1a4e465667d8e002a7a2f0c67f88a985 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Thu, 17 Nov 2022 23:22:15 +0700 Subject: [PATCH 09/13] revert unnecessary format --- .../ReimbursementAccount/RequestorStep.js | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 43bd09a13617..59cd6408f505 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -154,7 +154,9 @@ class RequestorStep extends React.Component { onCloseButtonPress={Navigation.dismissModal} /> {shouldShowOnfido ? ( - + ) : (
( - {this.props.translate('requestorStep.isControllingOfficer')} + + {this.props.translate('requestorStep.isControllingOfficer')} + )} style={[styles.mt4]} @@ -226,11 +230,19 @@ class RequestorStep extends React.Component { {`${this.props.translate('onfidoStep.facialScan')}`} {', '} - Link.openExternalLink('https://onfido.com/privacy/')} style={[styles.textMicro, styles.link]} accessibilityRole="link"> + Link.openExternalLink('https://onfido.com/privacy/')} + style={[styles.textMicro, styles.link]} + accessibilityRole="link" + > {`${this.props.translate('common.privacyPolicy')}`} {` ${this.props.translate('common.and')} `} - Link.openExternalLink('https://onfido.com/terms-of-service/')} style={[styles.textMicro, styles.link]} accessibilityRole="link"> + Link.openExternalLink('https://onfido.com/terms-of-service/')} + style={[styles.textMicro, styles.link]} + accessibilityRole="link" + > {`${this.props.translate('common.termsOfService')}`} From 739dafaaa76d7174a053279d3dba857f789e50aa Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Fri, 18 Nov 2022 07:48:18 +0700 Subject: [PATCH 10/13] update the zipcode example text --- src/languages/en.js | 2 +- src/languages/es.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index cda807f1aec4..e5ae4cc713b2 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -108,7 +108,7 @@ export default { maxParticipantsReached: ({count}) => `You've selected the maximum number (${count}) of participants.`, youAppearToBeOffline: 'You appear to be offline.', thisFeatureRequiresInternet: 'This feature requires an active internet connection to be used.', - zipCodeExample: 'e.x 12345, 12345-1234, 12345 1234', + zipCodeExample: 'e.g. 12345, 12345-1234, 12345 1234', }, attachmentPicker: { cameraPermissionRequired: 'Camera permission required', diff --git a/src/languages/es.js b/src/languages/es.js index 3f009b11e4e6..9c3f4cbb542f 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -108,7 +108,7 @@ export default { maxParticipantsReached: ({count}) => `Has seleccionado el número máximo (${count}) de participantes.`, youAppearToBeOffline: 'Parece que estás desconectado.', thisFeatureRequiresInternet: 'Esta función requiere una conexión a Internet activa para ser utilizada.', - zipCodeExample: 'e.x 12345, 12345-1234, 12345 1234', + zipCodeExample: 'p. ej. 12345, 12345-1234, 12345 1234', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', From 701e5438b228fce3946d53588cc33794d797ff18 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Fri, 18 Nov 2022 07:52:45 +0700 Subject: [PATCH 11/13] using isRequiredFulfilled to validate required fields --- .../ReimbursementAccount/RequestorStep.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 59cd6408f505..474ed78b4281 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -24,7 +24,6 @@ import Form from '../../components/Form'; const propTypes = { /** The bank account currently in setup */ - reimbursementAccount: reimbursementAccountPropTypes.isRequired, /** The token required to initialize the Onfido SDK */ @@ -75,15 +74,15 @@ class RequestorStep extends React.Component { validate(values) { const errors = {}; - if (!values.firstName) { + if (!ValidationUtils.isRequiredFulfilled(values.firstName)) { errors.firstName = this.props.translate('bankAccount.error.firstName'); } - if (!values.lastName) { + if (!ValidationUtils.isRequiredFulfilled(values.lastName)) { errors.lastName = this.props.translate('bankAccount.error.lastName'); } - if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { + if (!ValidationUtils.isRequiredFulfilled(values.dob)) { errors.dob = this.props.translate('bankAccount.error.dob'); } @@ -91,11 +90,11 @@ class RequestorStep extends React.Component { errors.dob = this.props.translate('bankAccount.error.age'); } - if (!values.ssnLast4 || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { + if (!ValidationUtils.isRequiredFulfilled(values.ssnLast4) || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { errors.ssnLast4 = this.props.translate('bankAccount.error.ssnLast4'); } - if (!values.requestorAddressStreet) { + if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressStreet)) { errors.requestorAddressStreet = this.props.translate('bankAccount.error.address'); } @@ -103,19 +102,19 @@ class RequestorStep extends React.Component { errors.requestorAddressStreet = this.props.translate('bankAccount.error.addressStreet'); } - if (!values.requestorAddressCity) { + if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressCity)) { errors.requestorAddressCity = this.props.translate('bankAccount.error.addressCity'); } - if (!values.requestorAddressState) { + if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressState)) { errors.requestorAddressState = this.props.translate('bankAccount.error.addressState'); } - if (!values.requestorAddressZipCode || !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { + if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressZipCode) || !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { errors.requestorAddressZipCode = this.props.translate('bankAccount.error.zipCode'); } - if (!values.isControllingOfficer) { + if (!ValidationUtils.isRequiredFulfilled(values.isControllingOfficer)) { errors.isControllingOfficer = this.props.translate('requestorStep.isControllingOfficerError'); } From bf91663c2986a0435e9940897638b52a94c13388 Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 23 Nov 2022 00:45:11 +0700 Subject: [PATCH 12/13] preventing the form to rerender when no errors state to update --- src/components/Form.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Form.js b/src/components/Form.js index b7b5f72edbd5..5bdf994bae79 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -125,7 +125,11 @@ class Form extends React.Component { const errors = _.pick(validationErrors, (inputValue, inputID) => ( Boolean(this.touchedInputs[inputID]) )); - this.setState({errors}); + + if (!_.isEqual(errors, this.state.errors)) { + this.setState({errors}); + } + return errors; } From c0bc0a7b74086ee44e3bdbda6ab258d118eef3dd Mon Sep 17 00:00:00 2001 From: Mohammad Luthfi Fathur Rahman Date: Wed, 23 Nov 2022 01:34:56 +0700 Subject: [PATCH 13/13] updating the zipcode input --- src/CONST.js | 2 +- src/pages/settings/Payments/AddDebitCardPage.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index fb0bd7ba6a2b..4efa4abc7ea5 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -104,7 +104,7 @@ const CONST = { }, MAX_LENGTH: { SSN: 4, - ZIP_CODE: 5, + ZIP_CODE: 10, }, }, INCORPORATION_TYPES: { diff --git a/src/pages/settings/Payments/AddDebitCardPage.js b/src/pages/settings/Payments/AddDebitCardPage.js index c60e261ce9c8..1025f9d9ef06 100644 --- a/src/pages/settings/Payments/AddDebitCardPage.js +++ b/src/pages/settings/Payments/AddDebitCardPage.js @@ -163,6 +163,7 @@ class DebitCardPage extends Component { label={this.props.translate('common.zip')} keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.ZIP_CODE} + hint={this.props.translate('common.zipCodeExample')} />