Skip to content

Commit ef649f5

Browse files
committed
finish redux form
1 parent e4f3655 commit ef649f5

File tree

10 files changed

+200
-2
lines changed

10 files changed

+200
-2
lines changed

server/client/package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"react-scripts": "1.0.10",
2121
"react-stripe-checkout": "^2.4.0",
2222
"redux": "^3.7.1",
23+
"redux-form": "^7.0.1",
2324
"redux-thunk": "^2.2.0"
2425
},
2526
"scripts": {

server/client/src/components/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as actions from '../actions';
66
import Header from './Header';
77
import Landing from './Landing';
88
import Dashboard from './Dashboard';
9-
const SurveyNew = () => <h2>SurveyNew</h2>;
9+
import SurveyNew from './surveys/SurveyNew';
1010

1111
class App extends Component {
1212
componentDidMount() {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SurveyField contains logic to render a single
2+
// label and text input
3+
import React from 'react';
4+
5+
export default ({ input, label, meta: { error, touched } }) => {
6+
return (
7+
<div>
8+
<label>{label}</label>
9+
<input {...input} style={{ marginBottom: '5px' }} />
10+
<div className="red-text" style={{ marginBottom: '20px' }}>
11+
{touched && error}
12+
</div>
13+
</div>
14+
);
15+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SurveyForm shows a form for a user to add input
2+
import _ from 'lodash';
3+
import React, { Component } from 'react';
4+
import { reduxForm, Field } from 'redux-form';
5+
import { Link } from 'react-router-dom';
6+
import SurveyField from './SurveyField';
7+
import validateEmails from '../../utils/validateEmails';
8+
import formFields from './formFields';
9+
10+
class SurveyForm extends Component {
11+
renderFields() {
12+
return _.map(formFields, ({ label, name }) => {
13+
return (
14+
<Field
15+
key={name}
16+
component={SurveyField}
17+
type="text"
18+
label={label}
19+
name={name}
20+
/>
21+
);
22+
});
23+
}
24+
25+
render() {
26+
return (
27+
<div>
28+
<form onSubmit={this.props.handleSubmit(this.props.onSurveySubmit)}>
29+
{this.renderFields()}
30+
<Link to="/surveys" className="red btn-flat white-text">
31+
Cancel
32+
</Link>
33+
<button type="submit" className="teal btn-flat right white-text">
34+
Next
35+
<i className="material-icons right">done</i>
36+
</button>
37+
</form>
38+
</div>
39+
);
40+
}
41+
}
42+
43+
function validate(values) {
44+
const errors = {};
45+
46+
errors.emails = validateEmails(values.emails || '');
47+
48+
_.each(formFields, ({ name }) => {
49+
if (!values[name]) {
50+
errors[name] = 'You must provide a value';
51+
}
52+
});
53+
54+
return errors;
55+
}
56+
57+
export default reduxForm({
58+
validate,
59+
form: 'surveyForm',
60+
destroyOnUnmount: false
61+
})(SurveyForm);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SurveyFormReview shows users their form inputs for review
2+
import _ from 'lodash';
3+
import React from 'react';
4+
import { connect } from 'react-redux';
5+
import formFields from './formFields';
6+
import * as actions from '../../actions';
7+
8+
const SurveyFormReview = ({ onCancel, formValues, submitSurvey }) => {
9+
const reviewFields = _.map(formFields, ({ name, label }) => {
10+
return (
11+
<div key={name}>
12+
<label>{label}</label>
13+
<div>
14+
{formValues[name]}
15+
</div>
16+
</div>
17+
);
18+
});
19+
20+
return (
21+
<div>
22+
<h5>Please confirm your entries</h5>
23+
{reviewFields}
24+
<button
25+
className="yellow darken-3 white-text btn-flat"
26+
onClick={onCancel}
27+
>
28+
Back
29+
</button>
30+
<button
31+
onClick={() => submitSurvey(formValues)}
32+
className="green btn-flat right white-text"
33+
>
34+
Send Survey
35+
<i className="material-icons right">email</i>
36+
</button>
37+
</div>
38+
);
39+
};
40+
41+
function mapStateToProps(state) {
42+
return { formValues: state.form.surveyForm.values };
43+
}
44+
45+
export default connect(mapStateToProps, actions)(SurveyFormReview);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SurveyNew shows SurveyForm and SurveyFormReview
2+
import React, { Component } from 'react';
3+
import { reduxForm } from 'redux-form';
4+
import SurveyForm from './SurveyForm';
5+
import SurveyFormReview from './SurveyFormReview';
6+
7+
class SurveyNew extends Component {
8+
state = { showFormReview: false };
9+
10+
renderContent() {
11+
if (this.state.showFormReview) {
12+
return (
13+
<SurveyFormReview
14+
onCancel={() => this.setState({ showFormReview: false })}
15+
/>
16+
);
17+
}
18+
19+
return (
20+
<SurveyForm
21+
onSurveySubmit={() => this.setState({ showFormReview: true })}
22+
/>
23+
);
24+
}
25+
26+
render() {
27+
return (
28+
<div>
29+
{this.renderContent()}
30+
</div>
31+
);
32+
}
33+
}
34+
35+
export default reduxForm({
36+
form: 'surveyForm'
37+
})(SurveyNew);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default [
2+
{ label: 'Campaign Title', name: 'title' },
3+
{ label: 'Subject Line', name: 'subject' },
4+
{ label: 'Email Body', name: 'body' },
5+
{ label: 'Recipient List', name: 'emails' }
6+
];
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { combineReducers } from 'redux';
2+
import { reducer as reduxForm } from 'redux-form';
23
import authReducer from './authReducer';
34

45
export default combineReducers({
5-
auth: authReducer
6+
auth: authReducer,
7+
form: reduxForm
68
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const re = /^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
2+
3+
export default emails => {
4+
const invalidEmails = emails
5+
.split(',')
6+
.map(email => email.trim())
7+
.filter(email => re.test(email) === false);
8+
9+
if (invalidEmails.length) {
10+
return `These emails are invalid: ${invalidEmails}`;
11+
}
12+
13+
return;
14+
};

0 commit comments

Comments
 (0)