mirror of
https://github.com/wassname/talk.git
synced 2026-08-13 12:40:11 +08:00
Ádding Debouncing for CheckAvailability, Valid Check form and Styling
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
});
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user