Skip to content

Commit 4eff5b5

Browse files
committed
Merge branch 'feature/async-username-validation' into dev
2 parents 1c09229 + 4e098d4 commit 4eff5b5

File tree

6 files changed

+76
-2
lines changed

6 files changed

+76
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ git flow feature finish upgrade-mirror
205205
### v1.0
206206

207207
- [x] Travis Testing
208-
- [ ] Asynchronous redux-form validation (detect duplicate username/email)
208+
- [x] Asynchronous redux-form validation (detect duplicate email)
209209
- [ ] Pagination Mechanism
210210

211211
### v1.0+

src/common/actions/formActions.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import formAPI from '../api/form';
2+
import { pushErrors } from '../actions/errorActions';
3+
4+
export const validateForm = (formName, fieldName, value) => {
5+
return (dispatch, getState) => {
6+
return formAPI(getState().apiEngine)
7+
.form(formName)
8+
.field(fieldName, value)
9+
.validate()
10+
.catch((err) => {
11+
let validationError = {};
12+
dispatch(pushErrors(err));
13+
validationError[fieldName] = 'Unable to validate';
14+
throw validationError;
15+
});
16+
};
17+
};

src/common/api/form.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default (apiEngine) => ({
2+
form: (formName) => ({
3+
field: (fieldName, value) => ({
4+
validate: () => apiEngine.post(
5+
`/api/forms/${formName}/fields/${fieldName}/validation`, {
6+
data: { value },
7+
}
8+
),
9+
}),
10+
}),
11+
});

src/common/components/forms/RegisterForm.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Field, reduxForm } from 'redux-form';
33
import Button from 'react-bootstrap/lib/Button';
44
// import validator from 'validator';
55
import userAPI from '../../api/user';
6+
import { validateForm } from '../../actions/formActions';
67
import { pushErrors } from '../../actions/errorActions';
78
import { Form, FormField, FormFooter } from '../utils/BsForm';
89

@@ -24,6 +25,17 @@ const validate = (values) => {
2425
return errors;
2526
};
2627

28+
let asyncValidate = (values, dispatch) => {
29+
return dispatch(validateForm('register', 'email', values.email))
30+
.then((json) => {
31+
let validationError = {};
32+
if (!json.isPassed) {
33+
validationError.email = json.message;
34+
throw validationError;
35+
}
36+
});
37+
};
38+
2739
class RegisterForm extends Component {
2840
constructor(props) {
2941
super(props);
@@ -46,6 +58,7 @@ class RegisterForm extends Component {
4658
const {
4759
handleSubmit,
4860
pristine,
61+
asyncValidating,
4962
submitting,
5063
invalid,
5164
} = this.props;
@@ -74,7 +87,10 @@ class RegisterForm extends Component {
7487
placeholder="Password"
7588
/>
7689
<FormFooter>
77-
<Button type="submit" disabled={pristine || submitting || invalid}>
90+
<Button
91+
type="submit"
92+
disabled={pristine || !!asyncValidating || submitting || invalid}
93+
>
7894
Register
7995
</Button>
8096
</FormFooter>
@@ -91,4 +107,6 @@ RegisterForm.contextTypes = {
91107
export default reduxForm({
92108
form: 'register',
93109
validate,
110+
asyncValidate,
111+
asyncBlurFields: ['email'],
94112
})(RegisterForm);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { handleDbError } from '../decorators/handleError';
2+
import User from '../models/User';
3+
4+
export default {
5+
register: {
6+
email(req, res) {
7+
User.findOne({
8+
'email.value': req.body.value,
9+
}, handleDbError(res)((user) => {
10+
if (user) {
11+
res.json({
12+
isPassed: false,
13+
message: 'The email is already registered',
14+
});
15+
} else {
16+
res.json({
17+
isPassed: true,
18+
});
19+
}
20+
}));
21+
},
22+
},
23+
};

src/server/routes/api.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import bodyParser from '../middlewares/bodyParser';
33
import authRequired from '../middlewares/authRequired';
44
import fileUpload from '../middlewares/fileUpload';
55
import userController from '../controllers/user';
6+
import formValidationController from '../controllers/formValidation';
67
import localeController from '../controllers/locale';
78
import todoController from '../controllers/todo';
89

@@ -24,6 +25,10 @@ export default ({ app }) => {
2425
filename: 'avatar.jpg',
2526
}).single('avatar'),
2627
userController.uploadAvatar);
28+
app.post('/api/forms/register/fields/email/validation',
29+
bodyParser.json,
30+
formValidationController.register.email
31+
);
2732
app.get('/api/locale/:locale', localeController.show);
2833
app.post('/api/todo', bodyParser.json, todoController.create);
2934
app.get('/api/todo', todoController.list);

0 commit comments

Comments
 (0)