Skip to content
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] ACHContractStep #13501

Merged
merged 33 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
05d3bb2
Replace ReimbursementAccountForm with Form
grgia Oct 19, 2022
4b089ce
Create ACHContractForm Onyx key and use it
grgia Oct 19, 2022
797e578
Clean up inputs
grgia Oct 19, 2022
780212a
Merge branch 'main' into georgia-ACH-form
grgia Nov 16, 2022
bee453f
Merge branch 'main' into georgia-ACH-form
grgia Nov 29, 2022
6abfb7e
New commit
grgia Dec 10, 2022
cb0fff7
Merge branch 'georgia-ACH-form' of github.com:Expensify/App into geor…
grgia Dec 10, 2022
292e3f3
Use corrext ONYX Form key, Use ReimbursementAccountUtils.getDefaultSt…
grgia Dec 12, 2022
57c61d3
Use dynamic keys for IdentityForm
grgia Dec 13, 2022
b816f5b
Remove consoles, reformat data sent on submit
grgia Dec 13, 2022
382b75a
Merge branch 'main' into georgia-ACH-form
grgia Dec 15, 2022
a379d39
Clean up code and remove unused ReimbursementAccountUtils
grgia Dec 15, 2022
3ad4f46
Set to empty array if hasOtherBeneficialOwners is checked
grgia Dec 15, 2022
fbe7e15
Fix bug where 4 forms are submitted even if requester owns 25%
grgia Dec 15, 2022
a36e8a8
Fix bug where checking the beneifial owners check doesn't open an ide…
grgia Dec 15, 2022
6a32616
Fix > 18 years old check
grgia Dec 16, 2022
49098db
Update comment to be more descriptive
grgia Dec 16, 2022
3f5c1cc
Fix long line
grgia Dec 16, 2022
ea35dc3
Merge branch 'main' into georgia-ACH-form
grgia Dec 16, 2022
b67bd24
Rename ownerID variable to ownerKey, add JSDocs and comments
grgia Dec 16, 2022
efed1c3
Use for loop for requiredFulfilled() calls
grgia Dec 19, 2022
8d167d8
Use Str.guid to generate keys, add section to FORMS.md
grgia Dec 22, 2022
ccb589b
Fix param type, use variable name instead of value for clarity
grgia Dec 23, 2022
d5085c6
Replace '.' with '_' for key to not be confused with dot notation
grgia Dec 23, 2022
45c97c1
Merge branch 'main' into georgia-ACH-form
grgia Jan 9, 2023
853a4f9
pass props from forms
grgia Jan 13, 2023
d4a95a0
Log change
grgia Jan 26, 2023
d27dc93
Use default values / draft values for initial render of form
grgia Jan 26, 2023
aee6c38
Merge branch 'main' into georgia-ACH-form
grgia Jan 31, 2023
a63e322
fix JS console errors
grgia Jan 31, 2023
5937ed9
Remove unused imports
grgia Jan 31, 2023
0df7ec4
use props instead of this.props
grgia Jan 31, 2023
27a6f27
Move proptype to single line
grgia Jan 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: this.props.draftValues,
grgia marked this conversation as resolved.
Show resolved Hide resolved
};

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