Skip to content

Commit 4e9f9df

Browse files
Added HOC to make it easier to create Redux Forms pages
1 parent 7a6acc3 commit 4e9f9df

File tree

8 files changed

+172
-142
lines changed

8 files changed

+172
-142
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from "react";
2+
import classNames from "classnames";
3+
4+
const ValidatingInputField = ({
5+
input,
6+
label,
7+
type,
8+
meta: { touched, error, warning }
9+
}) => (
10+
<div>
11+
<label>{label}</label>
12+
<div>
13+
<input
14+
className={classNames({ error: touched && error })}
15+
{...input}
16+
placeholder={label}
17+
type={type}
18+
/>
19+
{touched &&
20+
((error && <span className="error">{error}</span>) ||
21+
(warning && <span>{warning}</span>))}
22+
</div>
23+
</div>
24+
);
25+
26+
export default ValidatingInputField;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import ValidatingInputField from "./ValidatingInputField";
2+
3+
export default {
4+
ValidatingInputField
5+
};

src/modules/forms/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import components from "./components";
2+
import * as validators from "./validators";
3+
4+
export default {
5+
components,
6+
validators
7+
};

src/modules/forms/validators.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const required = value => {
2+
return (!isNaN(value) && +value) || (isNaN(value) && value !== undefined)
3+
? undefined
4+
: "Required";
5+
};

src/modules/wizard/components/ValidatingReduxFormWizardPageContainer.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,9 @@ export class ValidatingReduxFormWizardPageContainer extends React.Component {
6666

6767
transitionStateMachine(nextProps) {
6868
switch (nextProps.wizard.currentState) {
69-
case wizardStates.PAGE_INITIALIZED: {
70-
this.props.pageRequiresValidation();
71-
break;
72-
}
7369
case wizardStates.DONE_REQUESTED:
7470
case wizardStates.VALIDATION_REQUESTED: {
7571
this.startReduxFormsValidation();
76-
this.props.validating();
7772
break;
7873
}
7974
case wizardStates.VALIDATING:
@@ -83,7 +78,6 @@ export class ValidatingReduxFormWizardPageContainer extends React.Component {
8378
}
8479
case wizardStates.DISPOSING: {
8580
this.tryDestroyForm();
86-
this.props.finishedDisposing();
8781
break;
8882
}
8983
default: {
@@ -134,7 +128,7 @@ export class ValidatingReduxFormWizardPageContainer extends React.Component {
134128

135129
render() {
136130
return (
137-
<ValidatingWizardPage requiresValidation {...this.props}>
131+
<ValidatingWizardPage {...this.props}>
138132
{this.props.children}
139133
</ValidatingWizardPage>
140134
);
Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,69 @@
11
import React from "react";
22
import ValidatingReduxFormWizardPageContainer from "./ValidatingReduxFormWizardPageContainer";
3+
import { reduxForm, SubmissionError } from "redux-form";
4+
import _ from "lodash";
5+
import { getWizardErrors } from "../wizard.selectors";
6+
import { getState } from "../../store";
37

48
const WithReduxFormWizardPageValidation = (
59
wrappedComponent,
6-
{ formName, componentProps, handlesValidation, requiresInitialization = true }
7-
) => props => (
8-
<ValidatingReduxFormWizardPageContainer
9-
component={wrappedComponent}
10-
formName={formName}
11-
handlesValidation={handlesValidation}
12-
requiresInitialization={requiresInitialization}
13-
{...componentProps}
14-
{...props}
15-
/>
16-
);
10+
{
11+
formName,
12+
handlesValidation,
13+
requiresInitialization = false,
14+
isLastPage = false
15+
}
16+
) => {
17+
let config;
18+
19+
if (isLastPage) {
20+
config = {
21+
form: formName,
22+
destroyOnUnmount: false,
23+
forceUnregisterOnUnmount: true,
24+
keepDirtyOnReinitialize: true,
25+
enableReinitialize: true
26+
};
27+
} else {
28+
config = {
29+
form: formName,
30+
destroyOnUnmount: false,
31+
forceUnregisterOnUnmount: true,
32+
onSubmit: submit
33+
};
34+
}
35+
36+
const page = reduxForm(config)(wrappedComponent);
37+
38+
return props => (
39+
<ValidatingReduxFormWizardPageContainer
40+
formName={formName}
41+
handlesValidation={handlesValidation}
42+
requiresInitialization={requiresInitialization}
43+
{...props}
44+
>
45+
{React.createElement(page, props)}
46+
</ValidatingReduxFormWizardPageContainer>
47+
);
48+
};
49+
50+
// values left so we know it's available
51+
function submit() {
52+
// We can do form level validations here if needed using values
53+
54+
const wizardErrors = getWizardErrors(getState());
55+
56+
if (!_.isEmpty(wizardErrors)) {
57+
// We've got errors so let redux form know by returning a rejected promise
58+
return Promise.reject(
59+
new SubmissionError({
60+
...wizardErrors
61+
})
62+
);
63+
}
64+
65+
// No errors so let redux form know we are all good by returning a resolved promise
66+
return Promise.resolve();
67+
}
1768

1869
export default WithReduxFormWizardPageValidation;
Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,66 @@
11
import React from "react";
2-
import { reduxForm, Field } from "redux-form";
3-
import classNames from "classnames";
2+
import { Field, SubmissionError } from "redux-form";
3+
import { connect } from "react-redux";
44
import "./wizardExample.css";
55
import wizard from "../../../modules/wizard";
6+
import forms from "../../../modules/forms";
67

78
const {
8-
components: { ValidatingReduxFormWizardPage }
9-
} = wizard;
9+
components: { ValidatingInputField },
10+
validators: { required }
11+
} = forms;
1012

11-
const required = value => {
12-
return (!isNaN(value) && +value) || (isNaN(value) && value !== undefined)
13-
? undefined
14-
: "Required";
15-
};
13+
const {
14+
components: { WithReduxFormWizardPageValidation }
15+
} = wizard;
1616

17-
const ValidatingInputField = ({
18-
input,
19-
label,
20-
type,
21-
meta: { touched, error, warning }
22-
}) => (
23-
<div>
24-
<label>{label}</label>
25-
<div>
26-
<input
27-
className={classNames({ error: touched && error })}
28-
{...input}
29-
placeholder={label}
30-
type={type}
31-
/>
32-
{touched &&
33-
((error && <span className="error">{error}</span>) ||
34-
(warning && <span>{warning}</span>))}
35-
</div>
36-
</div>
17+
let PageWithReduxFormsValidations = ({ onSubmit, handleSubmit, ...rest }) => (
18+
<form onSubmit={handleSubmit(onSubmit)}>
19+
<Field
20+
component={ValidatingInputField}
21+
type="number"
22+
name="requiredNumber"
23+
validate={[required]}
24+
label="Required Number"
25+
/>
26+
</form>
3727
);
3828

39-
let PageWithReduxFormsValidations = ({ onSubmit, handleSubmit, ...rest }) => (
40-
<ValidatingReduxFormWizardPage {...rest}>
41-
<form onSubmit={handleSubmit(onSubmit)}>
42-
<Field
43-
component={ValidatingInputField}
44-
type="number"
45-
name="requiredNumber"
46-
validate={[required]}
47-
label="Required Number"
48-
/>
49-
</form>
50-
</ValidatingReduxFormWizardPage>
29+
PageWithReduxFormsValidations = WithReduxFormWizardPageValidation(
30+
PageWithReduxFormsValidations,
31+
{
32+
formName: "PageWithReduxFormsValidations",
33+
isLastPage: true
34+
}
5135
);
5236

53-
PageWithReduxFormsValidations = reduxForm({
54-
form: "PageWithReduxFormsValidations"
55-
})(PageWithReduxFormsValidations);
37+
class PageWithReduxFormsValidationsContainer extends React.Component {
38+
handleSubmit = values => {
39+
if (
40+
values.requiredText &&
41+
values.requiredText.toLowerCase() === "servererror"
42+
) {
43+
const errors = {
44+
requiredText: "A fake server error occurred. Please try again."
45+
};
46+
47+
const addEditPromoDetailsPage = 4;
48+
this.props.pageNotValid(addEditPromoDetailsPage);
49+
50+
throw new SubmissionError(errors);
51+
}
5652

57-
export default class PageWithReduxFormsValidationsContainer extends React.Component {
58-
handleSubmit(values) {
5953
alert(`Submit succeeded with values: ${JSON.stringify(values)}`);
6054

6155
return Promise.resolve("Success!");
62-
}
56+
};
6357

6458
render() {
65-
return (
66-
<PageWithReduxFormsValidations
67-
onSubmit={this.handleSubmit}
68-
{...this.props}
69-
/>
70-
);
59+
return <PageWithReduxFormsValidations onSubmit={this.handleSubmit} />;
7160
}
7261
}
62+
63+
export default connect(
64+
null,
65+
{ pageNotValid: wizard.actions.pageNotValid }
66+
)(PageWithReduxFormsValidationsContainer);
Lines changed: 19 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,31 @@
11
import React from "react";
2-
import { reduxForm, Field, SubmissionError } from "redux-form";
3-
import classNames from "classnames";
4-
import _ from "lodash";
2+
import { Field } from "redux-form";
53
import "./wizardExample.css";
6-
import { getState } from "../../../modules/store";
74
import wizard from "../../../modules/wizard";
5+
import forms from "../../../modules/forms";
86

97
const {
10-
selectors: { getWizardErrors }
11-
} = wizard;
8+
components: { ValidatingInputField },
9+
validators: { required }
10+
} = forms;
1211

1312
const {
14-
components: { ValidatingReduxFormWizardPage }
13+
components: { WithReduxFormWizardPageValidation }
1514
} = wizard;
1615

17-
const required = value => {
18-
return (!isNaN(value) && +value) || (isNaN(value) && value !== undefined)
19-
? undefined
20-
: "Required";
21-
};
22-
23-
const ValidatingInputField = ({
24-
input,
25-
label,
26-
type,
27-
meta: { touched, error, warning }
28-
}) => (
29-
<div>
30-
<label>{label}</label>
31-
<div>
32-
<input
33-
className={classNames({ error: touched && error })}
34-
{...input}
35-
placeholder={label}
36-
type={type}
37-
/>
38-
{touched &&
39-
((error && <span className="error">{error}</span>) ||
40-
(warning && <span>{warning}</span>))}
41-
</div>
42-
</div>
43-
);
44-
4516
const PageWithReduxFormsValidations = props => (
46-
<ValidatingReduxFormWizardPage {...props}>
47-
<form onSubmit={props.handleSubmit}>
48-
<Field
49-
component={ValidatingInputField}
50-
type="text"
51-
name="requiredText"
52-
validate={[required]}
53-
label="Required Text"
54-
/>
55-
</form>
56-
</ValidatingReduxFormWizardPage>
17+
<form onSubmit={props.handleSubmit}>
18+
<Field
19+
component={ValidatingInputField}
20+
type="text"
21+
name="requiredText"
22+
validate={[required]}
23+
label="Required Text"
24+
/>
25+
</form>
5726
);
5827

59-
// values left so we know it's available
60-
function submit() {
61-
// We can do form level validations here if needed using values
62-
63-
const wizardErrors = getWizardErrors(getState());
64-
65-
if (!_.isEmpty(wizardErrors)) {
66-
// We've got errors so let redux form know by returning a rejected promise
67-
return Promise.reject(
68-
new SubmissionError({
69-
...wizardErrors
70-
})
71-
);
72-
}
73-
74-
// No errors so let redux form know we are all good by returning a resolved promise
75-
return Promise.resolve();
76-
}
77-
78-
export default reduxForm({
79-
form: "PageWithReduxFormsValidations",
80-
destroyOnUnmount: false,
81-
forceUnregisterOnUnmount: true,
82-
onSubmit: submit
83-
})(PageWithReduxFormsValidations);
28+
export default WithReduxFormWizardPageValidation(
29+
PageWithReduxFormsValidations,
30+
{ formName: "PageWithReduxFormsValidations" }
31+
);

0 commit comments

Comments
 (0)