Ádding Debouncing for CheckAvailability, Valid Check form and Styling

This commit is contained in:
Belen Curcio
2016-11-16 20:56:05 -03:00
parent bd47495b63
commit 60c17fc973
13 changed files with 137 additions and 97 deletions
+10 -3
View File
@@ -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
+2 -2
View File
@@ -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'
};
@@ -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) {
+1 -1
View File
@@ -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))
};
+13 -11
View File
@@ -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)
+1 -1
View File
@@ -11,7 +11,7 @@ const FormField = ({className, showErrors = false, errorMsg, label, ...props}) =
name={props.id}
{...props}
/>
{showErrors && errorMsg && <span className={styles.errorMsg}>{errorMsg}</span>}
{showErrors && errorMsg && <span className={styles.errorMsg}><span className={styles.attention}>!</span>{errorMsg}</span>}
</div>
);
@@ -41,14 +41,16 @@ const SignInContent = ({handleChange, formData, ...props}) => (
value={formData.password}
onChange={handleChange}
/>
{
!props.auth.isLoading ?
<Button type="submit" cStyle="black" className={styles.signInButton}>
{lang.t('signIn.signIn')}
</Button>
:
<Spinner />
}
<div className={styles.action}>
{
!props.auth.isLoading ?
<Button type="submit" cStyle="black" className={styles.signInButton}>
{lang.t('signIn.signIn')}
</Button>
:
<Spinner />
}
</div>
</form>
<div className={styles.footer}>
<span><a onClick={() => props.changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')}</a></span>
@@ -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 && <Alert>This email is not available.</Alert> }
<FormField
id="username"
id="displayName"
type="text"
label={lang.t('signIn.username')}
value={formData.username}
label={lang.t('signIn.displayName')}
value={formData.displayName}
showErrors={props.showErrors}
errorMsg={props.errors.username}
errorMsg={props.errors.displayName}
onChange={handleChange}
/>
{ !props.auth.displayNameAvailable && <Alert>This username is not available.</Alert> }
<FormField
id="password"
type="password"
@@ -55,7 +54,9 @@ const SignUpContent = ({handleChange, formData, ...props}) => (
showErrors={props.showErrors}
errorMsg={props.errors.password}
onChange={handleChange}
minLength="8"
/>
{ !props.errors.password && <span className={styles.hint}> Password must be at least 8 characters. </span> }
<FormField
id="confirmPassword"
type="password"
@@ -64,15 +65,18 @@ const SignUpContent = ({handleChange, formData, ...props}) => (
showErrors={props.showErrors}
errorMsg={props.errors.confirmPassword}
onChange={handleChange}
minLength="8"
/>
{
!props.auth.isLoading ?
<Button type="submit" cStyle="black" className={styles.signInButton}>
{lang.t('signIn.signUp')}
</Button>
:
<Spinner />
}
<div className={styles.action}>
{
!props.auth.isLoading ?
<Button type="submit" cStyle="black" className={styles.signInButton}>
{lang.t('signIn.signUp')}
</Button>
:
<Spinner />
}
</div>
</form>
<div className={styles.footer}>
<span>
+28 -2
View File
@@ -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;
}
@@ -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 (
<div>
<Button onClick={showSignInDialog}>
Sign in to comment
</Button>
<SignDialog
open={auth.showSignInDialog}
open={showSignInDialog}
view={auth.view}
showErrors={showErrors}
formData={formData}
errors={errors}
{...this}
{...this.state}
{...this.props}
/>
</div>
@@ -147,7 +150,7 @@ class SignInContainer extends Component {
}
}
const mapStateToProps = (state) => ({
const mapStateToProps = state => ({
auth: state.auth.toJS()
});
+6 -4
View File
@@ -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'
}
}
};
+1
View File
@@ -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",
+3 -8
View File
@@ -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);