From 628c4dfd9b4f0d0dd6dda124812b6d58d9f2f785 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Sat, 11 Mar 2017 00:48:25 -0500
Subject: [PATCH 1/8] added account page showing username and email
---
client/components/Nav.jsx | 5 ++
.../modules/User/components/AccountForm.jsx | 84 +++++++++++++++++++
client/modules/User/pages/AccountView.jsx | 81 ++++++++++++++++++
client/routes.jsx | 2 +
4 files changed, 172 insertions(+)
create mode 100644 client/modules/User/components/AccountForm.jsx
create mode 100644 client/modules/User/pages/AccountView.jsx
diff --git a/client/components/Nav.jsx b/client/components/Nav.jsx
index c0f9778a72..82b73274d9 100644
--- a/client/components/Nav.jsx
+++ b/client/components/Nav.jsx
@@ -136,6 +136,11 @@ class Nav extends React.PureComponent {
My sketches
+
+
+ My account
+
+
-
+
{currentPassword.touched && currentPassword.error && {currentPassword.error}}
-
+
{newPassword.touched && newPassword.error && {newPassword.error}}
-
+
);
}
AccountForm.propTypes = {
fields: PropTypes.shape({
+ username: PropTypes.object.isRequired,
+ email: PropTypes.object.isRequired,
currentPassword: PropTypes.object.isRequired,
newPassword: PropTypes.object.isRequired
}).isRequired,
- user: PropTypes.shape({
- email: PropTypes.string.isRequired,
- username: PropTypes.string.isRequired,
- }).isRequired,
handleSubmit: PropTypes.func.isRequired,
- validateAndLoginUser: PropTypes.func.isRequired,
+ updateSettings: PropTypes.func.isRequired,
submitting: PropTypes.bool,
+ invalid: PropTypes.bool,
pristine: PropTypes.bool,
- previousPath: PropTypes.string.isRequired
};
AccountForm.defaultProps = {
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index f7c2e9bdfa..4cb6b6ed53 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -1,10 +1,12 @@
import React, { PropTypes } from 'react';
import { reduxForm } from 'redux-form';
-import { Link, browserHistory } from 'react-router';
+import { bindActionCreators } from 'redux';
+import { browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
-import { validateAndLoginUser } from '../actions';
+import axios from 'axios';
+import { updateSettings } from '../actions';
import AccountForm from '../components/AccountForm';
-// import GithubButton from '../components/GithubButton';
+
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -48,34 +50,74 @@ class AccountView extends React.Component {
function mapStateToProps(state) {
return {
+ initialValues: state.user, // <- initialValues for reduxForm
user: state.user,
previousPath: state.ide.previousPath
};
}
-function mapDispatchToProps() {
- return {
- validateAndLoginUser
- };
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({ updateSettings }, dispatch);
+}
+
+function asyncValidate(formProps, dispatch, props) {
+ const fieldToValidate = props.form._active;
+ if (fieldToValidate) {
+ const queryParams = {};
+ queryParams[fieldToValidate] = formProps[fieldToValidate];
+ queryParams.check_type = fieldToValidate;
+ return axios.get('/api/signup/duplicate_check', { params: queryParams })
+ .then((response) => {
+ if (response.data.exists) {
+ const error = {};
+ error[fieldToValidate] = response.data.message;
+ throw error;
+ }
+ });
+ }
+ return Promise.resolve(true).then(() => {});
}
function validate(formProps) {
const errors = {};
- if (!formProps.email) {
- errors.email = 'Please enter an email';
+
+ if (!formProps.username) {
+ errors.username = 'Please enter a username.';
+ } else if (!formProps.username.match(/^.{1,20}$/)) {
+ errors.username = 'Username must be less than 20 characters.';
+ } else if (!formProps.username.match(/^[a-zA-Z0-9._-]{1,20}$/)) {
+ errors.username = 'Username must only consist of numbers, letters, periods, dashes, and underscores.';
}
- if (!formProps.password) {
- errors.password = 'Please enter a password';
+
+ if (!formProps.email) {
+ errors.email = 'Please enter an email.';
+ } else if (!formProps.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
+ errors.email = 'Please enter a valid email address.';
}
+
+ // if (!formProps.currentPassword) {
+ // errors.currentPassword = 'Please enter current password';
+ // }
+ // if (!formProps.newPassword) {
+ // errors.newPassword = 'Please enter a new password';
+ // }
+
return errors;
}
+function onSubmitFail(errors) {
+ console.log(errors);
+}
+
AccountView.propTypes = {
previousPath: PropTypes.string.isRequired
};
export default reduxForm({
- form: 'login',
- fields: ['currentPassword', 'newPassword'],
- validate
+ form: 'updateAllSettings',
+ fields: ['username', 'email', 'currentPassword', 'newPassword'],
+ onSubmitFail,
+ validate,
+ asyncValidate,
+ asyncBlurFields: ['username', 'email']
}, mapStateToProps, mapDispatchToProps)(AccountView);
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index 306f7ee5b2..27aa7f663c 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -182,3 +182,28 @@ export function userExists(username, callback) {
user ? callback(true) : callback(false)
));
}
+
+export function updateSettings(req, res) {
+ User.findById(req.user.id, (err, user) => {
+ if (err) {
+ res.status(500).json({ error: err });
+ return;
+ }
+ if (!user) {
+ res.status(404).json({ error: 'Document not found' });
+ return;
+ }
+
+ user.email = req.body.email;
+ user.username = req.body.username;
+
+ user.save((saveErr) => {
+ if (saveErr) {
+ res.status(500).json({ error: saveErr });
+ return;
+ }
+
+ res.json(user);
+ });
+ });
+}
diff --git a/server/routes/user.routes.js b/server/routes/user.routes.js
index a295e96c45..b3468cd87d 100644
--- a/server/routes/user.routes.js
+++ b/server/routes/user.routes.js
@@ -15,4 +15,6 @@ router.route('/reset-password/:token').get(UserController.validateResetPasswordT
router.route('/reset-password/:token').post(UserController.updatePassword);
+router.route('/account').put(UserController.updateSettings);
+
export default router;
From 28b2d5625014a0c5445fc608fe66903437aed47d Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Wed, 15 Mar 2017 06:54:03 -0400
Subject: [PATCH 3/8] validate current password and add new password
---
client/constants.js | 1 +
client/modules/User/actions.js | 6 +++++-
client/modules/User/pages/AccountView.jsx | 7 -------
server/controllers/user.controller.js | 19 +++++++++++++++++++
4 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/client/constants.js b/client/constants.js
index b6444700c4..9c5121feb2 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -96,6 +96,7 @@ export const RESET_INFINITE_LOOPS = 'RESET_INFINITE_LOOPS';
export const RESET_PASSWORD_INITIATE = 'RESET_PASSWORD_INITIATE';
export const RESET_PASSWORD_RESET = 'RESET_PASSWORD_RESET';
export const INVALID_RESET_PASSWORD_TOKEN = 'INVALID_RESET_PASSWORD_TOKEN';
+export const INVALID_CURRENT_PASSWORD = 'INVALID_CURRENT_PASSWORD';
// eventually, handle errors more specifically and better
export const ERROR = 'ERROR';
diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js
index 948bed20b5..99326a6388 100644
--- a/client/modules/User/actions.js
+++ b/client/modules/User/actions.js
@@ -170,11 +170,15 @@ export function saveSettingsSuccess(user) {
export function updateSettings(formValues) {
return (dispatch) => {
+ console.log(formValues);
axios.put(`${ROOT_URL}/account`, formValues, { withCredentials: true })
.then((response) => {
dispatch(saveSettingsSuccess(response.data));
browserHistory.push('/');
})
- .catch(response => dispatch(authError(response.data.error)));
+ .catch(response => dispatch({
+ type: ActionTypes.INVALID_CURRENT_PASSWORD,
+ message: response.data.error
+ }));
};
}
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index 4cb6b6ed53..971946e320 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -95,13 +95,6 @@ function validate(formProps) {
errors.email = 'Please enter a valid email address.';
}
- // if (!formProps.currentPassword) {
- // errors.currentPassword = 'Please enter current password';
- // }
- // if (!formProps.newPassword) {
- // errors.newPassword = 'Please enter a new password';
- // }
-
return errors;
}
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index 27aa7f663c..ac3418037f 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -197,6 +197,25 @@ export function updateSettings(req, res) {
user.email = req.body.email;
user.username = req.body.username;
+ let validPassword = true;
+ if (req.body.currentPassword) {
+ validPassword = false;
+ user.comparePassword(req.body.currentPassword, (err, isMatch) => {
+ if (err) throw err;
+ if (!isMatch) {
+ validPassword = false;
+ } else {
+ validPassword = true;
+ user.password = req.body.newPassword;
+ }
+ });
+ }
+
+ if (!validPassword) {
+ res.status(401).json({ error: 'Invalid current password.' });
+ return;
+ }
+
user.save((saveErr) => {
if (saveErr) {
res.status(500).json({ error: saveErr });
From e082d1a4d6144865c69ed8a6ac8c7a6ac95e5276 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Wed, 15 Mar 2017 22:08:29 -0400
Subject: [PATCH 4/8] reject promise with error for reduxForm submit-validation
for current password
---
client/constants.js | 2 +-
client/modules/User/actions.js | 21 +++----------------
.../modules/User/components/AccountForm.jsx | 4 ++--
client/modules/User/pages/AccountView.jsx | 7 +------
client/modules/User/reducers.js | 1 +
server/controllers/user.controller.js | 2 +-
6 files changed, 9 insertions(+), 28 deletions(-)
diff --git a/client/constants.js b/client/constants.js
index 9c5121feb2..e6c71eed40 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -96,7 +96,7 @@ export const RESET_INFINITE_LOOPS = 'RESET_INFINITE_LOOPS';
export const RESET_PASSWORD_INITIATE = 'RESET_PASSWORD_INITIATE';
export const RESET_PASSWORD_RESET = 'RESET_PASSWORD_RESET';
export const INVALID_RESET_PASSWORD_TOKEN = 'INVALID_RESET_PASSWORD_TOKEN';
-export const INVALID_CURRENT_PASSWORD = 'INVALID_CURRENT_PASSWORD';
+
// eventually, handle errors more specifically and better
export const ERROR = 'ERROR';
diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js
index 99326a6388..cf9512efc6 100644
--- a/client/modules/User/actions.js
+++ b/client/modules/User/actions.js
@@ -161,24 +161,9 @@ export function updatePassword(token, formValues) {
};
}
-export function saveSettingsSuccess(user) {
- return {
- type: ActionTypes.AUTH_USER,
- user
- };
-}
-
export function updateSettings(formValues) {
- return (dispatch) => {
- console.log(formValues);
+ return dispatch =>
axios.put(`${ROOT_URL}/account`, formValues, { withCredentials: true })
- .then((response) => {
- dispatch(saveSettingsSuccess(response.data));
- browserHistory.push('/');
- })
- .catch(response => dispatch({
- type: ActionTypes.INVALID_CURRENT_PASSWORD,
- message: response.data.error
- }));
- };
+ .then(response => browserHistory.push('/'))
+ .catch(response => Promise.reject({ currentPassword: response.data.error }));
}
diff --git a/client/modules/User/components/AccountForm.jsx b/client/modules/User/components/AccountForm.jsx
index 0c7fd61ddd..b8980d9f4d 100644
--- a/client/modules/User/components/AccountForm.jsx
+++ b/client/modules/User/components/AccountForm.jsx
@@ -18,7 +18,7 @@ function AccountForm(props) {
aria-label="email"
type="text"
id="email"
- {...email}
+ {...domOnlyProps(email)}
/>
{email.touched && email.error && {email.error}}
@@ -30,7 +30,7 @@ function AccountForm(props) {
type="text"
id="username"
defaultValue={username}
- {...username}
+ {...domOnlyProps(username)}
/>
{username.touched && username.error && {username.error}}
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index 971946e320..4960e08398 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -98,10 +98,6 @@ function validate(formProps) {
return errors;
}
-function onSubmitFail(errors) {
- console.log(errors);
-}
-
AccountView.propTypes = {
previousPath: PropTypes.string.isRequired
};
@@ -109,8 +105,7 @@ AccountView.propTypes = {
export default reduxForm({
form: 'updateAllSettings',
fields: ['username', 'email', 'currentPassword', 'newPassword'],
- onSubmitFail,
validate,
asyncValidate,
- asyncBlurFields: ['username', 'email']
+ asyncBlurFields: ['username', 'email', 'currentPassword']
}, mapStateToProps, mapDispatchToProps)(AccountView);
diff --git a/client/modules/User/reducers.js b/client/modules/User/reducers.js
index 04220f584b..8debbf677d 100644
--- a/client/modules/User/reducers.js
+++ b/client/modules/User/reducers.js
@@ -19,6 +19,7 @@ const user = (state = { authenticated: false }, action) => {
return Object.assign({}, state, { resetPasswordInitiate: false });
case ActionTypes.INVALID_RESET_PASSWORD_TOKEN:
return Object.assign({}, state, { resetPasswordInvalid: true });
+
default:
return state;
}
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index ac3418037f..0a79e9af87 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -212,7 +212,7 @@ export function updateSettings(req, res) {
}
if (!validPassword) {
- res.status(401).json({ error: 'Invalid current password.' });
+ res.status(401).json({ error: 'Current password is invalid.' });
return;
}
From 8d4b71e92b52ac2ab4b40f9227f58bfb6982c289 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Wed, 15 Mar 2017 22:46:18 -0400
Subject: [PATCH 5/8] updated user reducer to handle setting sucess and server
side async
---
client/constants.js | 2 ++
client/modules/User/actions.js | 12 +++++++++++-
client/modules/User/reducers.js | 3 ++-
server/controllers/user.controller.js | 26 ++++++++++++--------------
4 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/client/constants.js b/client/constants.js
index e6c71eed40..3cc8f104a7 100644
--- a/client/constants.js
+++ b/client/constants.js
@@ -23,6 +23,8 @@ export const AUTH_USER = 'AUTH_USER';
export const UNAUTH_USER = 'UNAUTH_USER';
export const AUTH_ERROR = 'AUTH_ERROR';
+export const SETTINGS_UPDATED = 'SETTINGS_UPDATED';
+
export const SET_PROJECT_NAME = 'SET_PROJECT_NAME';
export const PROJECT_SAVE_SUCCESS = 'PROJECT_SAVE_SUCCESS';
diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js
index cf9512efc6..e8a3953cf9 100644
--- a/client/modules/User/actions.js
+++ b/client/modules/User/actions.js
@@ -161,9 +161,19 @@ export function updatePassword(token, formValues) {
};
}
+export function updateSettingsSuccess(user) {
+ return {
+ type: ActionTypes.SETTINGS_UPDATED,
+ user
+ };
+}
+
export function updateSettings(formValues) {
return dispatch =>
axios.put(`${ROOT_URL}/account`, formValues, { withCredentials: true })
- .then(response => browserHistory.push('/'))
+ .then((response) => {
+ dispatch(updateSettingsSuccess(response.data));
+ browserHistory.push('/');
+ })
.catch(response => Promise.reject({ currentPassword: response.data.error }));
}
diff --git a/client/modules/User/reducers.js b/client/modules/User/reducers.js
index 8debbf677d..5554a11f44 100644
--- a/client/modules/User/reducers.js
+++ b/client/modules/User/reducers.js
@@ -19,7 +19,8 @@ const user = (state = { authenticated: false }, action) => {
return Object.assign({}, state, { resetPasswordInitiate: false });
case ActionTypes.INVALID_RESET_PASSWORD_TOKEN:
return Object.assign({}, state, { resetPasswordInvalid: true });
-
+ case ActionTypes.SETTINGS_UPDATED:
+ return { ...state, ...action.user };
default:
return state;
}
diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js
index 0a79e9af87..ffe6876ed7 100644
--- a/server/controllers/user.controller.js
+++ b/server/controllers/user.controller.js
@@ -197,32 +197,30 @@ export function updateSettings(req, res) {
user.email = req.body.email;
user.username = req.body.username;
- let validPassword = true;
if (req.body.currentPassword) {
- validPassword = false;
user.comparePassword(req.body.currentPassword, (err, isMatch) => {
if (err) throw err;
if (!isMatch) {
- validPassword = false;
+ res.status(401).json({ error: 'Current password is invalid.' });
+ return;
} else {
- validPassword = true;
user.password = req.body.newPassword;
+ saveUser(res, user);
}
});
+ } else {
+ saveUser(res, user);
}
+ });
+}
- if (!validPassword) {
- res.status(401).json({ error: 'Current password is invalid.' });
+export function saveUser(res, user) {
+ user.save((saveErr) => {
+ if (saveErr) {
+ res.status(500).json({ error: saveErr });
return;
}
- user.save((saveErr) => {
- if (saveErr) {
- res.status(500).json({ error: saveErr });
- return;
- }
-
- res.json(user);
- });
+ res.json(user);
});
}
From fca28077171789e93cd3b66607f1766b74883b09 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Wed, 15 Mar 2017 23:09:19 -0400
Subject: [PATCH 6/8] warning if there is current password but no new password
---
client/modules/User/pages/AccountView.jsx | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index 4960e08398..2736b7e3d8 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -95,6 +95,10 @@ function validate(formProps) {
errors.email = 'Please enter a valid email address.';
}
+ if (formProps.currentPassword && !formProps.newPassword) {
+ errors.newPassword = 'Please enter a new password or leave the current password empty.';
+ }
+
return errors;
}
From 13966078ca12d399ea7874d0b54fd4ffde0da871 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Thu, 16 Mar 2017 02:18:02 -0400
Subject: [PATCH 7/8] fixes logout button
---
client/styles/components/_nav.scss | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/client/styles/components/_nav.scss b/client/styles/components/_nav.scss
index 84f91fdd09..2eaaccf47d 100644
--- a/client/styles/components/_nav.scss
+++ b/client/styles/components/_nav.scss
@@ -56,7 +56,7 @@
.nav__item-spacer {
@include themify() {
color: map-get($theme-map, 'inactive-text-color');
- }
+ }
padding: 0 #{15 / $base-font-size}rem;
}
@@ -65,12 +65,16 @@
width: 100%;
}
-.nav__dropdown a {
+.nav__dropdown a, button {
@include themify() {
color: getThemifyVariable('secondary-text-color');
}
}
+.nav__dropdown button {
+ padding: 0;
+}
+
.nav__dropdown a:hover {
@include themify() {
color: getThemifyVariable('primary-text-color');
From b33b8093be997453e0c407333a31112648f45fc1 Mon Sep 17 00:00:00 2001
From: Yining Shi
Date: Thu, 16 Mar 2017 17:30:38 -0400
Subject: [PATCH 8/8] import validate function, fixes logout style
---
client/modules/User/pages/AccountView.jsx | 27 +----------
client/modules/User/pages/LoginView.jsx | 14 +-----
client/modules/User/pages/SignupView.jsx | 34 +------------
client/utils/reduxFormUtils.js | 58 +++++++++++++++++++++++
4 files changed, 64 insertions(+), 69 deletions(-)
diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx
index 2736b7e3d8..00397c0acd 100644
--- a/client/modules/User/pages/AccountView.jsx
+++ b/client/modules/User/pages/AccountView.jsx
@@ -6,6 +6,7 @@ import InlineSVG from 'react-inlinesvg';
import axios from 'axios';
import { updateSettings } from '../actions';
import AccountForm from '../components/AccountForm';
+import { validateSettings } from '../../../utils/reduxFormUtils';
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -78,30 +79,6 @@ function asyncValidate(formProps, dispatch, props) {
return Promise.resolve(true).then(() => {});
}
-function validate(formProps) {
- const errors = {};
-
- if (!formProps.username) {
- errors.username = 'Please enter a username.';
- } else if (!formProps.username.match(/^.{1,20}$/)) {
- errors.username = 'Username must be less than 20 characters.';
- } else if (!formProps.username.match(/^[a-zA-Z0-9._-]{1,20}$/)) {
- errors.username = 'Username must only consist of numbers, letters, periods, dashes, and underscores.';
- }
-
- if (!formProps.email) {
- errors.email = 'Please enter an email.';
- } else if (!formProps.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
- errors.email = 'Please enter a valid email address.';
- }
-
- if (formProps.currentPassword && !formProps.newPassword) {
- errors.newPassword = 'Please enter a new password or leave the current password empty.';
- }
-
- return errors;
-}
-
AccountView.propTypes = {
previousPath: PropTypes.string.isRequired
};
@@ -109,7 +86,7 @@ AccountView.propTypes = {
export default reduxForm({
form: 'updateAllSettings',
fields: ['username', 'email', 'currentPassword', 'newPassword'],
- validate,
+ validate: validateSettings,
asyncValidate,
asyncBlurFields: ['username', 'email', 'currentPassword']
}, mapStateToProps, mapDispatchToProps)(AccountView);
diff --git a/client/modules/User/pages/LoginView.jsx b/client/modules/User/pages/LoginView.jsx
index 255d640826..b25e50535b 100644
--- a/client/modules/User/pages/LoginView.jsx
+++ b/client/modules/User/pages/LoginView.jsx
@@ -4,6 +4,7 @@ import { Link, browserHistory } from 'react-router';
import InlineSVG from 'react-inlinesvg';
import { validateAndLoginUser } from '../actions';
import LoginForm from '../components/LoginForm';
+import { validateLogin } from '../../../utils/reduxFormUtils';
// import GithubButton from '../components/GithubButton';
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -67,17 +68,6 @@ function mapDispatchToProps() {
};
}
-function validate(formProps) {
- const errors = {};
- if (!formProps.email) {
- errors.email = 'Please enter an email';
- }
- if (!formProps.password) {
- errors.password = 'Please enter a password';
- }
- return errors;
-}
-
LoginView.propTypes = {
previousPath: PropTypes.string.isRequired
};
@@ -85,5 +75,5 @@ LoginView.propTypes = {
export default reduxForm({
form: 'login',
fields: ['email', 'password'],
- validate
+ validate: validateLogin
}, mapStateToProps, mapDispatchToProps)(LoginView);
diff --git a/client/modules/User/pages/SignupView.jsx b/client/modules/User/pages/SignupView.jsx
index d575995703..47278271a7 100644
--- a/client/modules/User/pages/SignupView.jsx
+++ b/client/modules/User/pages/SignupView.jsx
@@ -6,6 +6,7 @@ import InlineSVG from 'react-inlinesvg';
import { reduxForm } from 'redux-form';
import * as UserActions from '../actions';
import SignupForm from '../components/SignupForm';
+import { validateSignup } from '../../../utils/reduxFormUtils';
const exitUrl = require('../../../images/exit.svg');
const logoUrl = require('../../../images/p5js-logo.svg');
@@ -78,37 +79,6 @@ function asyncValidate(formProps, dispatch, props) {
return Promise.resolve(true).then(() => {});
}
-function validate(formProps) {
- const errors = {};
-
- if (!formProps.username) {
- errors.username = 'Please enter a username.';
- } else if (!formProps.username.match(/^.{1,20}$/)) {
- errors.username = 'Username must be less than 20 characters.';
- } else if (!formProps.username.match(/^[a-zA-Z0-9._-]{1,20}$/)) {
- errors.username = 'Username must only consist of numbers, letters, periods, dashes, and underscores.';
- }
-
- if (!formProps.email) {
- errors.email = 'Please enter an email.';
- } else if (!formProps.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
- errors.email = 'Please enter a valid email address.';
- }
-
- if (!formProps.password) {
- errors.password = 'Please enter a password';
- }
- if (!formProps.confirmPassword) {
- errors.confirmPassword = 'Please enter a password confirmation';
- }
-
- if (formProps.password !== formProps.confirmPassword) {
- errors.password = 'Passwords must match';
- }
-
- return errors;
-}
-
function onSubmitFail(errors) {
console.log(errors);
}
@@ -121,7 +91,7 @@ export default reduxForm({
form: 'signup',
fields: ['username', 'email', 'password', 'confirmPassword'],
onSubmitFail,
- validate,
+ validate: validateSignup,
asyncValidate,
asyncBlurFields: ['username', 'email']
}, mapStateToProps, mapDispatchToProps)(SignupView);
diff --git a/client/utils/reduxFormUtils.js b/client/utils/reduxFormUtils.js
index 8b4b120545..c2c68fa0c5 100644
--- a/client/utils/reduxFormUtils.js
+++ b/client/utils/reduxFormUtils.js
@@ -14,3 +14,61 @@ export const domOnlyProps = ({
error,
...domProps }) => domProps;
/* eslint-enable */
+
+function validateNameEmail(formProps, errors) {
+ if (!formProps.username) {
+ errors.username = 'Please enter a username.';
+ } else if (!formProps.username.match(/^.{1,20}$/)) {
+ errors.username = 'Username must be less than 20 characters.';
+ } else if (!formProps.username.match(/^[a-zA-Z0-9._-]{1,20}$/)) {
+ errors.username = 'Username must only consist of numbers, letters, periods, dashes, and underscores.';
+ }
+
+ if (!formProps.email) {
+ errors.email = 'Please enter an email.';
+ } else if (!formProps.email.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i)) {
+ errors.email = 'Please enter a valid email address.';
+ }
+}
+
+export function validateSettings(formProps) {
+ const errors = {};
+
+ validateNameEmail(formProps, errors);
+
+ if (formProps.currentPassword && !formProps.newPassword) {
+ errors.newPassword = 'Please enter a new password or leave the current password empty.';
+ }
+
+ return errors;
+}
+
+export function validateLogin(formProps) {
+ const errors = {};
+ if (!formProps.email) {
+ errors.email = 'Please enter an email';
+ }
+ if (!formProps.password) {
+ errors.password = 'Please enter a password';
+ }
+ return errors;
+}
+
+export function validateSignup(formProps) {
+ const errors = {};
+
+ validateNameEmail(formProps, errors);
+
+ if (!formProps.password) {
+ errors.password = 'Please enter a password';
+ }
+ if (!formProps.confirmPassword) {
+ errors.confirmPassword = 'Please enter a password confirmation';
+ }
+
+ if (formProps.password !== formProps.confirmPassword) {
+ errors.password = 'Passwords must match';
+ }
+
+ return errors;
+}