From bd47495b633495d69f3427f2b96cbc20101cd1a5 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Wed, 16 Nov 2016 16:55:47 -0300 Subject: [PATCH] User Email Availability check --- client/coral-framework/actions/auth.js | 40 +++++++++++++---- client/coral-framework/constants/auth.js | 7 +++ client/coral-framework/helpers/response.js | 2 + client/coral-framework/reducers/auth.js | 23 +++++++--- .../coral-sign-in/components/SignInContent.js | 8 ++-- .../coral-sign-in/components/SignUpContent.js | 9 ++-- .../containers/SignInContainer.js | 24 ++++++---- routes/api/user/index.js | 44 +++++++++++++++++++ 8 files changed, 128 insertions(+), 29 deletions(-) diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 896fb9aab..e25eb4174 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -30,8 +30,8 @@ export const fetchSignIn = (formData) => dispatch => { // Sign In - Facebook const signInFacebookRequest = () => ({type: actions.FETCH_SIGNIN_FACEBOOK_REQUEST}); -const signInFacebookSuccess = (user) => ({type: actions.FETCH_SIGNIN_FACEBOOK_SUCCESS, user}); -const signInFacebookFailure = (error) => ({type: actions.FETCH_SIGNIN_FACEBOOK_FAILURE, error}); +const signInFacebookSuccess = user => ({type: actions.FETCH_SIGNIN_FACEBOOK_SUCCESS, user}); +const signInFacebookFailure = error => ({type: actions.FETCH_SIGNIN_FACEBOOK_FAILURE, error}); export const fetchSignInFacebook = () => dispatch => { dispatch(signInFacebookRequest()); @@ -58,15 +58,15 @@ export const facebookCallback = (err, data) => dispatch => { // Sign Up Actions const signUpRequest = () => ({type: actions.FETCH_SIGNUP_REQUEST}); -const signUpSuccess = () => ({type: actions.FETCH_SIGNUP_SUCCESS}); -const signUpFailure = () => ({type: actions.FETCH_SIGNUP_FAILURE}); +const signUpSuccess = user => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); +const signUpFailure = error => ({type: actions.FETCH_SIGNUP_FAILURE, error}); -export const fetchSignUp = () => dispatch => { +export const fetchSignUp = formData => dispatch => { dispatch(signUpRequest()); - fetch(`${base}/auth`, getInit('POST')) + fetch(`${base}/user`, getInit('POST', formData)) .then(handleResp) - .then(() => dispatch(signUpSuccess())) - .catch(error => dispatch(signUpFailure(error))); + .then(({user}) => signUpSuccess(user)) + .catch((error) => signUpFailure(error)); }; // Forgot Password Actions @@ -97,3 +97,27 @@ export const logout = () => dispatch => { .catch(error => dispatch(logOutFailure(error))); }; +// Availability Checks Actions + +const availabilityRequest = () => ({type: actions.FETCH_AVAILABILITY_REQUEST}); +const availabilitySuccess = () => ({type: actions.FETCH_AVAILABILITY_SUCCESS}); +const availabilityFailure = () => ({type: actions.FETCH_AVAILABILITY_FAILURE}); + +const availableField = field => ({type: actions.AVAILABLE_FIELD, field}); +const unavailableField = field => ({type: actions.UNAVAILABLE_FIELD, field}); + +export const fetchCheckAvailability = formData => dispatch => { + dispatch(availabilityRequest()); + fetch(`${base}/user/availability`, getInit('POST', formData)) + .then(handleResp) + .then(({status}) => { + const [field] = Object.keys(formData); + dispatch(availabilitySuccess()); + if (status === 'available') { + return dispatch(availableField(field)); + } + return dispatch(unavailableField(field)); + }) + .catch((error) => availabilityFailure(error)); +}; + diff --git a/client/coral-framework/constants/auth.js b/client/coral-framework/constants/auth.js index 06558d513..5c0135f58 100644 --- a/client/coral-framework/constants/auth.js +++ b/client/coral-framework/constants/auth.js @@ -23,3 +23,10 @@ export const FETCH_FORGOT_PASSWORD_FAILURE = 'FETCH_FORGOT_PASSWORD_FAILURE'; export const LOGOUT_REQUEST = 'LOGOUT_REQUEST'; export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'; + +export const FETCH_AVAILABILITY_REQUEST = 'FETCH_AVAILABILITY_REQUEST'; +export const FETCH_AVAILABILITY_SUCCESS = 'FETCH_AVAILABILITY_SUCCESS'; +export const FETCH_AVAILABILITY_FAILURE = 'FETCH_AVAILABILITY_FAILURE'; + +export const AVAILABLE_FIELD = 'AVAILABLE_FIELD'; +export const UNAVAILABLE_FIELD = 'UNAVAILABLE_FIELD'; diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index bccfc5a04..a18bd155f 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -20,6 +20,8 @@ export const getInit = (method, body) => { export const handleResp = res => { if (res.status === 401) { throw new Error('Not Authorized to make this request'); + } else if (res.status === 500) { + throw new Error(res.json()); } else if (res.status > 399) { throw new Error('Error! Status ', res.status); } else if (res.status === 204) { diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js index 001c98346..10ac121e7 100644 --- a/client/coral-framework/reducers/auth.js +++ b/client/coral-framework/reducers/auth.js @@ -10,21 +10,24 @@ import { FETCH_SIGNIN_SUCCESS, FETCH_SIGNIN_FACEBOOK_SUCCESS, FETCH_SIGNIN_FACEBOOK_FAILURE, - LOGOUT_SUCCESS + LOGOUT_SUCCESS, + FETCH_SIGNUP_FAILURE, + AVAILABLE_FIELD, + UNAVAILABLE_FIELD } from '../constants/auth'; const initialState = Map({ - auth: Map(), isLoading: false, loggedIn: false, user: null, showSignInDialog: false, view: 'SIGNIN', - signInError: '' + signInError: '', + signUpError: '', + emailAvailable: true, + displayNameAvailable: true, }); -export const getEmail = state => state.auth.formData.email; - export default function auth (state = initialState, action) { switch (action.type) { case SHOW_SIGNIN_DIALOG : @@ -60,10 +63,20 @@ export default function auth (state = initialState, action) { return state .set('error', action.error) .set('user', null); + case FETCH_SIGNUP_FAILURE: + console.log(action); + return state + .set('signUpError', action.error); case LOGOUT_SUCCESS: return state .set('loggedIn', false) .set('user', null); + case AVAILABLE_FIELD: + return state + .set(`${action.field}Available`, true); + case UNAVAILABLE_FIELD: + return state + .set(`${action.field}Available`, false); default : return state; } diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index aa3b712fa..2e22c0696 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -1,11 +1,9 @@ import React from 'react'; -import styles from './styles.css'; - import Button from 'coral-ui/components/Button'; import FormField from './FormField'; import Alert from './Alert'; import Spinner from 'coral-ui/components/Spinner'; - +import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); @@ -27,7 +25,7 @@ const SignInContent = ({handleChange, formData, ...props}) => ( {lang.t('signIn.or')} - { props.signInError && {props.signInError} } + { props.auth.signInError && {props.auth.signInError} }
( onChange={handleChange} /> { - !props.isLoading ? + !props.auth.isLoading ? diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index db005368f..2ae6267dc 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -1,8 +1,9 @@ import React from 'react'; -import styles from './styles.css'; import FormField from './FormField'; +import Alert from './Alert'; import Button from 'coral-ui/components/Button'; import Spinner from 'coral-ui/components/Spinner'; +import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); @@ -24,6 +25,7 @@ const SignUpContent = ({handleChange, formData, ...props}) => ( {lang.t('signIn.or')} + { props.auth.signUpError && {props.auth.signUpError} } ( errorMsg={props.errors.email} onChange={handleChange} /> + { !props.auth.emailAvailable && This email is not available. } ( errorMsg={props.errors.username} onChange={handleChange} /> + { !props.auth.displayNameAvailable && This username is not available. } ( errorMsg={props.errors.confirmPassword} onChange={handleChange} /> - { - !props.isLoading ? + !props.auth.isLoading ? diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index 1fa3ff053..471c0c166 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -15,7 +15,8 @@ import { hideSignInDialog, fetchSignInFacebook, fetchForgotPassword, - facebookCallback + facebookCallback, + fetchCheckAvailability } from '../../coral-framework/actions/auth'; class SignInContainer extends Component { @@ -76,6 +77,13 @@ class SignInContainer extends Component { ...state, errors })); + + // Check Availability + + if (name === 'email' || name === 'displayName') { + this.props.checkAvailability({[name]: value}); + } + } } @@ -126,14 +134,11 @@ class SignInContainer extends Component { Sign in to comment @@ -142,7 +147,9 @@ class SignInContainer extends Component { } } -const mapStateToProps = ({auth}) => ({auth}); +const mapStateToProps = (state) => ({ + auth: state.auth.toJS() +}); const mapDispatchToProps = dispatch => ({ facebookCallback: (err, data) => dispatch(facebookCallback(err, data)), @@ -152,7 +159,8 @@ const mapDispatchToProps = dispatch => ({ fetchForgotPassword: (formData) => dispatch(fetchForgotPassword(formData)), showSignInDialog: () => dispatch(showSignInDialog()), changeView: (view) => dispatch(changeView(view)), - handleClose: () => dispatch(hideSignInDialog()) + handleClose: () => dispatch(hideSignInDialog()), + checkAvailability: (formData) => dispatch(fetchCheckAvailability(formData)) }); export default connect( diff --git a/routes/api/user/index.js b/routes/api/user/index.js index 18872eab7..4b428be33 100644 --- a/routes/api/user/index.js +++ b/routes/api/user/index.js @@ -60,4 +60,48 @@ router.get('/', (req, res, next) => { .catch(next); }); +router.post('/', (req, res, next) => { + const {email, password, displayName} = req.query; + + User + .createLocalUser(email, password, displayName) + .then(user => { + res.status(201).send(user); + }) + .catch(err => { + next(err); + }); +}); + +router.post('/availability', (req, res, next) => { + const {email} = req.body; + + if (email) { + return User.count({ + profiles: { + $elemMatch: { + id: email, + provider: 'local' + } + } + }) + .then(count => { + if (count) { + res.json({ + status: 'unavailable' + }); + } else { + res.json({ + status: 'available' + }); + } + }) + .catch(err => { + next(err); + }); + } + + return res.status(404).send('Wrong parameters'); +}); + module.exports = router;