diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index e25eb4174..19fa2c499 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -23,7 +23,10 @@ export const fetchSignIn = (formData) => dispatch => { dispatch(signInRequest()); fetch(`${base}/auth/local`, getInit('POST', formData)) .then(handleResp) - .then(({user}) => dispatch(signInSuccess(user))) + .then(({user}) => { + dispatch(hideSignInDialog()); + dispatch(signInSuccess(user)); + }) .catch(() => dispatch(signInFailure('Email and/or password combination incorrect.'))); }; @@ -49,6 +52,7 @@ export const facebookCallback = (err, data) => dispatch => { } try { dispatch(signInFacebookSuccess(JSON.parse(data))); + dispatch(hideSignInDialog()); } catch (err) { dispatch(signInFacebookFailure(err)); return; @@ -65,8 +69,11 @@ export const fetchSignUp = formData => dispatch => { dispatch(signUpRequest()); fetch(`${base}/user`, getInit('POST', formData)) .then(handleResp) - .then(({user}) => signUpSuccess(user)) - .catch((error) => signUpFailure(error)); + .then(({user}) => { + dispatch(signUpSuccess(user)); + dispatch(hideSignInDialog()); + }) + .catch((error) => dispatch(signUpFailure(error))); }; // Forgot Password Actions diff --git a/client/coral-framework/helpers/error.js b/client/coral-framework/helpers/error.js index 2674bc55b..735ad7a5d 100644 --- a/client/coral-framework/helpers/error.js +++ b/client/coral-framework/helpers/error.js @@ -1,6 +1,6 @@ export default { email: 'Not a valid E-Mail', password: 'Password must be at least 8 characters', - username: 'Username is too short', - confirmPassword: 'Passwords do not match' + displayName: 'Display name is too short', + confirmPassword: 'Passwords don`t match. Please, check again' }; diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index a18bd155f..bccfc5a04 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -20,8 +20,6 @@ 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/helpers/validate.js b/client/coral-framework/helpers/validate.js index 9fda4b1c2..8c5ebd36f 100644 --- a/client/coral-framework/helpers/validate.js +++ b/client/coral-framework/helpers/validate.js @@ -2,5 +2,5 @@ export default { email: email => (/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(email)), password: pass => (/^(?=.{8,}).*$/.test(pass)), confirmPassword: () => true, - username: username => (/^(?=.{3,}).*$/.test(username)) + displayName: displayName => (/^(?=.{3,}).*$/.test(displayName)) }; diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js index 10ac121e7..c2bdc20db 100644 --- a/client/coral-framework/reducers/auth.js +++ b/client/coral-framework/reducers/auth.js @@ -25,7 +25,6 @@ const initialState = Map({ signInError: '', signUpError: '', emailAvailable: true, - displayNameAvailable: true, }); export default function auth (state = initialState, action) { @@ -34,7 +33,14 @@ export default function auth (state = initialState, action) { return state .set('showSignInDialog', true); case HIDE_SIGNIN_DIALOG : - return initialState; + return state.merge(Map({ + isLoading: false, + showSignInDialog: false, + view: 'SIGNIN', + signInError: '', + signUpError: '', + emailAvailable: true, + })); case CHANGE_VIEW : return state .set('view', action.view); @@ -43,22 +49,18 @@ export default function auth (state = initialState, action) { case FETCH_SIGNIN_REQUEST: return state .set('isLoading', true); + case FETCH_SIGNIN_SUCCESS: + return state + .set('loggedIn', true) + .set('user', action.user); case FETCH_SIGNIN_FAILURE: return state .set('isLoading', false) .set('signInError', action.error); - case FETCH_SIGNIN_SUCCESS: - return state - .set('signInError', '') - .set('isLoading', false) - .set('loggedIn', true) - .set('user', action.user) - .set('showSignInDialog', false); case FETCH_SIGNIN_FACEBOOK_SUCCESS: return state .set('user', action.user) - .set('loggedIn', true) - .set('showSignInDialog', false); + .set('loggedIn', true); case FETCH_SIGNIN_FACEBOOK_FAILURE: return state .set('error', action.error) diff --git a/client/coral-sign-in/components/FormField.js b/client/coral-sign-in/components/FormField.js index 62e50e637..ceb2d939e 100644 --- a/client/coral-sign-in/components/FormField.js +++ b/client/coral-sign-in/components/FormField.js @@ -11,7 +11,7 @@ const FormField = ({className, showErrors = false, errorMsg, label, ...props}) = name={props.id} {...props} /> - {showErrors && errorMsg && {errorMsg}} + {showErrors && errorMsg && !{errorMsg}} ); diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index 2e22c0696..8aa688133 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -41,14 +41,16 @@ const SignInContent = ({handleChange, formData, ...props}) => ( value={formData.password} onChange={handleChange} /> - { - !props.auth.isLoading ? - - : - - } +
+ { + !props.auth.isLoading ? + + : + + } +
props.changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')} diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 2ae6267dc..adc377dbf 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -32,21 +32,20 @@ const SignUpContent = ({handleChange, formData, ...props}) => ( type="email" label={lang.t('signIn.email')} value={formData.email} - showErrors={props.showErrors} - errorMsg={props.errors.email} + showErrors={!props.auth.emailAvailable || props.showErrors} + errorMsg={!props.auth.emailAvailable ? lang.t('signIn.emailInUse') : props.errors.email} onChange={handleChange} + autoFocus /> - { !props.auth.emailAvailable && This email is not available. } - { !props.auth.displayNameAvailable && This username is not available. } ( showErrors={props.showErrors} errorMsg={props.errors.password} onChange={handleChange} + minLength="8" /> + { !props.errors.password && Password must be at least 8 characters. } ( showErrors={props.showErrors} errorMsg={props.errors.confirmPassword} onChange={handleChange} + minLength="8" /> - { - !props.auth.isLoading ? - - : - - } +
+ { + !props.auth.isLoading ? + + : + + } +
diff --git a/client/coral-sign-in/components/styles.css b/client/coral-sign-in/components/styles.css index a7c14d891..9cd7bd326 100644 --- a/client/coral-sign-in/components/styles.css +++ b/client/coral-sign-in/components/styles.css @@ -15,6 +15,10 @@ font-size: 1.2em; } +.formField { + margin-top: 15px; +} + .formField label { font-size: 1.08em; font-weight: bold; @@ -74,10 +78,10 @@ } input.error{ - border: solid 1px #f44336; + border: solid 2px #f44336; } -.errorMsg { +.errorMsg, .hint { color: grey; font-weight: 600; padding: 3px 0 16px; @@ -86,6 +90,7 @@ input.error{ .alert { padding: 10px; margin-bottom: 20px; + border-radius: 2px; } .alert--success { @@ -103,4 +108,25 @@ input.error{ color: #2c69b6; cursor: pointer; margin: 0 5px; +} + +.attention { + display: inline-block; + width: 15px; + height: 15px; + background: #B71C1C; + color: #FFEBEE; + font-weight: bolder; + padding: 4px; + vertical-align: middle; + border-radius: 20px; + box-sizing: border-box; + font-size: 9px; + line-height: 7px; + text-align: center; + margin-right: 5px; +} + +.action { + margin-top: 15px; } \ No newline at end of file diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index 471c0c166..7a5ae51ac 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -1,11 +1,12 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; +import debounce from 'lodash.debounce'; import SignDialog from '../components/SignDialog'; import Button from 'coral-ui/components/Button'; import validate from 'coral-framework/helpers/validate'; -import error from 'coral-framework/helpers/error'; +import errorMsj from 'coral-framework/helpers/error'; import { changeView, @@ -23,7 +24,7 @@ class SignInContainer extends Component { initialState = { formData: { email: '', - username: '', + displayName: '', password: '', confirmPassword: '' }, @@ -39,7 +40,7 @@ class SignInContainer extends Component { this.handleSignIn = this.handleSignIn.bind(this); this.handleClose = this.handleClose.bind(this); this.cleanState = this.cleanState.bind(this); - this.validation = this.validation.bind(this); + this.addError = this.addError.bind(this); } componentDidMount() { @@ -52,72 +53,77 @@ class SignInContainer extends Component { handleChange(e) { const {name, value} = e.target; - this.validation(name, value, this.state.formData); - this.setState(state => ({ ...state, formData: { ...state.formData, [name]: value } + }), () => { + this.validation(name, value); + }); + } + + addError(name, error) { + return this.setState(state => ({ + errors: { + ...state.errors, + [name]: error + } })); } validation(name, value) { - if (!validate[name](value)) { - this.setState(state => ({ - errors: { - ...state.errors, - [name]: error[name] - } - })); + const {addError} = this; + const {formData} = this.state; + const {checkAvailability} = this.props; + + if (!value.length) { + addError(name, 'Please, fill this field'); + } else if (name === 'confirmPassword' && formData.confirmPassword !== formData.password) { + addError(name, 'Passwords don`t match. Please, check again.'); + } else if (!validate[name](value)) { + addError(name, errorMsj[name]); } else { const { [name]: prop, ...errors } = this.state.errors; // eslint-disable-line - this.setState(state => ({ - ...state, - errors - })); - - // Check Availability - - if (name === 'email' || name === 'displayName') { - this.props.checkAvailability({[name]: value}); + // Removes Error + this.setState(state => ({...state, errors})); + // Checks Email Availability + if (name === 'email') { + debounce(checkAvailability({[name]: value}), 250); } - } } isCompleted() { const {formData} = this.state; - return !Object.keys(formData).filter(prop => !formData[prop].length).length; + const {emailAvailable} = this.props.auth; + return !Object.keys(formData).filter(prop => !formData[prop].length).length && emailAvailable; } displayErrors(show = true) { - this.setState({ - showErrors: show - }); + this.setState({showErrors: show}); } handleSignUp(e) { e.preventDefault(); + const {errors} = this.state; this.displayErrors(); - if (this.isCompleted()) { - console.log('Is Completed!!'); - } else { - console.log('Is not Completed!!'); + if (this.isCompleted() && !Object.keys(errors).length) { + this.props.fetchSignUp(this.state.formData); + this.cleanState(); } - this.props.fetchSignUp(this.state.formData); } handleSignIn(e) { e.preventDefault(); - this.displayErrors(); this.props.fetchSignIn(this.state.formData); + this.cleanState(); } handleClose() { - this.cleanState(); this.props.hideSignInDialog(); + this.cleanState(); } changeView(view) { @@ -127,19 +133,16 @@ class SignInContainer extends Component { render() { const {auth, showSignInDialog} = this.props; - const {errors, showErrors, formData} = this.state; return (
@@ -147,7 +150,7 @@ class SignInContainer extends Component { } } -const mapStateToProps = (state) => ({ +const mapStateToProps = state => ({ auth: state.auth.toJS() }); diff --git a/client/coral-sign-in/translations.js b/client/coral-sign-in/translations.js index a0fd7015e..fdf7de0a0 100644 --- a/client/coral-sign-in/translations.js +++ b/client/coral-sign-in/translations.js @@ -13,9 +13,10 @@ export default { register: 'Register', signUp: 'Sign Up', confirmPassword: 'Confirm Password', - username: 'Username', + displayName: 'Display Name', alreadyHaveAnAccount: 'Already have an account?', - recoverPassword: 'Recover password' + recoverPassword: 'Recover password', + emailInUse: 'Email address already in use' } }, es: { @@ -32,9 +33,10 @@ export default { register: 'Regístrate', signUp: 'Registro', confirmPassword: 'Confirmar Contraseña', - username: 'Usuario', + displayName: 'Nombre', alreadyHaveAnAccount: 'Ya tienes una cuenta?', - recoverPassword: 'Recuperar contraseña' + recoverPassword: 'Recuperar contraseña', + emailInUse: 'Este email se encuentra en uso' } } }; diff --git a/package.json b/package.json index 4341483af..b913aefce 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "express": "^4.14.0", "express-session": "^1.14.2", "helmet": "^3.1.0", + "lodash.debounce": "^4.0.8", "mongoose": "^4.6.5", "morgan": "^1.7.0", "passport": "^0.3.2", diff --git a/routes/api/user/index.js b/routes/api/user/index.js index 4b428be33..e8bc90ac2 100644 --- a/routes/api/user/index.js +++ b/routes/api/user/index.js @@ -61,7 +61,7 @@ router.get('/', (req, res, next) => { }); router.post('/', (req, res, next) => { - const {email, password, displayName} = req.query; + const {email, password, displayName} = req.body; User .createLocalUser(email, password, displayName) @@ -87,14 +87,9 @@ router.post('/availability', (req, res, next) => { }) .then(count => { if (count) { - res.json({ - status: 'unavailable' - }); - } else { - res.json({ - status: 'available' - }); + return res.json({status: 'unavailable'}); } + return res.json({status: 'available'}); }) .catch(err => { next(err);