Skip to content

Commit

Permalink
Merge pull request #13501 from Expensify/georgia-ACH-form
Browse files Browse the repository at this point in the history
[Form Refactor] ACHContractStep
  • Loading branch information
luacmartins authored Feb 1, 2023
2 parents c5e3d0b + 27a6f27 commit f214132
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 232 deletions.
9 changes: 9 additions & 0 deletions contributingGuides/FORMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,15 @@ Form.js will automatically provide the following props to any input with the inp
- onBlur: An onBlur handler that calls validate.
- onInputChange: An onChange handler that saves draft values and calls validate for that input (inputA). Passing an inputID as a second param allows inputA to manipulate the input value of the provided inputID (inputB).

## Dynamic Form Inputs

It's possible to conditionally render inputs (or more complex components with multiple inputs) inside a form. For example, an IdentityForm might be nested as input for a Form component.
In order for Form to track the nested values properly, each field must have a unique identifier. It's not safe to use an index because adding or removing fields from the child Form component will not update these internal keys. Therefore, we will need to define keys and dynamically access the correlating child form data for validation/submission.

To generate these unique keys, use `Str.guid()`.

An example of this can be seen in the [ACHContractStep](https://github.com/Expensify/App/blob/f2973f88cfc0d36c0dbe285201d3ed5e12f29d87/src/pages/ReimbursementAccount/ACHContractStep.js), where each key is stored in an array in state, and IdentityForms are dynamically rendered based on which keys are present in the array.

### Safe Area Padding

Any `Form.js` that has a button will also add safe area padding by default. If the `<Form/>` is inside a `<ScreenWrapper>` we will want to disable the default safe area padding applied there e.g.
Expand Down
12 changes: 8 additions & 4 deletions src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ const propTypes = {
/** Callback to submit the form */
onSubmit: PropTypes.func.isRequired,

children: PropTypes.node.isRequired,
/** Children to render. */
children: PropTypes.oneOfType([
PropTypes.func,
PropTypes.node,
]).isRequired,

/* Onyx Props */

Expand Down Expand Up @@ -95,7 +99,7 @@ class Form extends React.Component {

this.state = {
errors: {},
inputValues: {},
inputValues: props.draftValues,
};

this.formRef = React.createRef(null);
Expand Down Expand Up @@ -186,7 +190,7 @@ class Form extends React.Component {
/**
* Loops over Form's children and automatically supplies Form props to them
*
* @param {Array} children - An array containing all Form children
* @param {Array | Function | Node} children - An array containing all Form children
* @returns {React.Component}
*/
childrenWrapperWithProps(children) {
Expand Down Expand Up @@ -280,7 +284,7 @@ class Form extends React.Component {
render() {
const scrollViewContent = safeAreaPaddingBottomStyle => (
<FormSubmit style={StyleSheet.flatten([this.props.style, safeAreaPaddingBottomStyle])} onSubmit={this.submit}>
{this.childrenWrapperWithProps(this.props.children)}
{this.childrenWrapperWithProps(_.isFunction(this.props.children) ? this.props.children({inputValues: this.state.inputValues}) : this.props.children)}
{this.props.isSubmitButtonVisible && (
<FormAlertWithSubmitButton
buttonText={this.props.submitButtonText}
Expand Down
27 changes: 1 addition & 26 deletions src/libs/ReimbursementAccountUtils.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import lodashGet from 'lodash/get';
import * as BankAccounts from './actions/BankAccounts';
import FormHelper from './FormHelper';

const formHelper = new FormHelper({
errorPath: 'reimbursementAccount.errorFields',
setErrors: BankAccounts.setBankAccountFormValidationErrors,
});

const getErrors = props => formHelper.getErrors(props);
const clearError = (props, path) => formHelper.clearError(props, path);
const clearErrors = (props, paths) => formHelper.clearErrors(props, paths);

/**
* Get the default state for input fields in the VBA flow
Expand All @@ -26,21 +15,7 @@ function getDefaultStateForField(reimbursementAccountDraft, reimbursementAccount
|| lodashGet(reimbursementAccount, ['achData', fieldName], defaultValue);
}

/**
* @param {Object} props
* @param {Object} errorTranslationKeys
* @param {String} inputKey
* @returns {String}
*/
function getErrorText(props, errorTranslationKeys, inputKey) {
const errors = getErrors(props) || {};
return errors[inputKey] ? props.translate(errorTranslationKeys[inputKey]) : '';
}

export {
// eslint-disable-next-line import/prefer-default-export
getDefaultStateForField,
getErrors,
clearError,
clearErrors,
getErrorText,
};
Loading

0 comments on commit f214132

Please sign in to comment.