Skip to content

Commit f214132

Browse files
authored
Merge pull request #13501 from Expensify/georgia-ACH-form
[Form Refactor] ACHContractStep
2 parents c5e3d0b + 27a6f27 commit f214132

File tree

5 files changed

+224
-232
lines changed

5 files changed

+224
-232
lines changed

contributingGuides/FORMS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,15 @@ Form.js will automatically provide the following props to any input with the inp
250250
- onBlur: An onBlur handler that calls validate.
251251
- 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).
252252

253+
## Dynamic Form Inputs
254+
255+
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.
256+
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.
257+
258+
To generate these unique keys, use `Str.guid()`.
259+
260+
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.
261+
253262
### Safe Area Padding
254263

255264
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.

src/components/Form.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ const propTypes = {
3131
/** Callback to submit the form */
3232
onSubmit: PropTypes.func.isRequired,
3333

34-
children: PropTypes.node.isRequired,
34+
/** Children to render. */
35+
children: PropTypes.oneOfType([
36+
PropTypes.func,
37+
PropTypes.node,
38+
]).isRequired,
3539

3640
/* Onyx Props */
3741

@@ -95,7 +99,7 @@ class Form extends React.Component {
9599

96100
this.state = {
97101
errors: {},
98-
inputValues: {},
102+
inputValues: props.draftValues,
99103
};
100104

101105
this.formRef = React.createRef(null);
@@ -186,7 +190,7 @@ class Form extends React.Component {
186190
/**
187191
* Loops over Form's children and automatically supplies Form props to them
188192
*
189-
* @param {Array} children - An array containing all Form children
193+
* @param {Array | Function | Node} children - An array containing all Form children
190194
* @returns {React.Component}
191195
*/
192196
childrenWrapperWithProps(children) {
@@ -280,7 +284,7 @@ class Form extends React.Component {
280284
render() {
281285
const scrollViewContent = safeAreaPaddingBottomStyle => (
282286
<FormSubmit style={StyleSheet.flatten([this.props.style, safeAreaPaddingBottomStyle])} onSubmit={this.submit}>
283-
{this.childrenWrapperWithProps(this.props.children)}
287+
{this.childrenWrapperWithProps(_.isFunction(this.props.children) ? this.props.children({inputValues: this.state.inputValues}) : this.props.children)}
284288
{this.props.isSubmitButtonVisible && (
285289
<FormAlertWithSubmitButton
286290
buttonText={this.props.submitButtonText}

src/libs/ReimbursementAccountUtils.js

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
11
import lodashGet from 'lodash/get';
2-
import * as BankAccounts from './actions/BankAccounts';
3-
import FormHelper from './FormHelper';
4-
5-
const formHelper = new FormHelper({
6-
errorPath: 'reimbursementAccount.errorFields',
7-
setErrors: BankAccounts.setBankAccountFormValidationErrors,
8-
});
9-
10-
const getErrors = props => formHelper.getErrors(props);
11-
const clearError = (props, path) => formHelper.clearError(props, path);
12-
const clearErrors = (props, paths) => formHelper.clearErrors(props, paths);
132

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

29-
/**
30-
* @param {Object} props
31-
* @param {Object} errorTranslationKeys
32-
* @param {String} inputKey
33-
* @returns {String}
34-
*/
35-
function getErrorText(props, errorTranslationKeys, inputKey) {
36-
const errors = getErrors(props) || {};
37-
return errors[inputKey] ? props.translate(errorTranslationKeys[inputKey]) : '';
38-
}
39-
4018
export {
19+
// eslint-disable-next-line import/prefer-default-export
4120
getDefaultStateForField,
42-
getErrors,
43-
clearError,
44-
clearErrors,
45-
getErrorText,
4621
};

0 commit comments

Comments
 (0)