Revive resend verification feature

This commit is contained in:
Chi Vinh Le
2017-10-23 18:46:41 +02:00
parent a3216dd33e
commit d75ae3aca8
10 changed files with 150 additions and 102 deletions
+14 -9
View File
@@ -23,6 +23,10 @@ export const hideSignInDialog = () => (dispatch) => {
dispatch({type: actions.HIDE_SIGNIN_DIALOG});
};
export const resetSignInDialog = () => (dispatch) => {
dispatch({type: actions.HIDE_SIGNIN_DIALOG});
};
export const focusSignInDialog = () => ({
type: actions.FOCUS_SIGNIN_DIALOG,
});
@@ -94,8 +98,9 @@ export const cleanState = () => ({
// Sign In Actions
const signInRequest = () => ({
type: actions.FETCH_SIGNIN_REQUEST
const signInRequest = (email) => ({
type: actions.FETCH_SIGNIN_REQUEST,
email,
});
const signInFailure = (error) => ({
@@ -122,7 +127,7 @@ export const handleAuthToken = (token) => (dispatch, _, {storage}) => {
export const fetchSignIn = (formData) => {
return (dispatch, _, {rest}) => {
dispatch(signInRequest());
dispatch(signInRequest(formData.email));
return rest('/auth/local', {method: 'POST', body: formData})
.then(({token}) => {
@@ -144,8 +149,7 @@ export const fetchSignIn = (formData) => {
// invalid credentials
dispatch(signInFailure(t('error.email_password'), error.metadata));
} else {
const str = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(signInFailure(str));
dispatch(signInFailure(error));
}
});
};
@@ -349,8 +353,9 @@ const verifyEmailSuccess = () => ({
type: actions.VERIFY_EMAIL_SUCCESS
});
const verifyEmailFailure = () => ({
type: actions.VERIFY_EMAIL_FAILURE
const verifyEmailFailure = (error) => ({
type: actions.VERIFY_EMAIL_FAILURE,
error,
});
export const requestConfirmEmail = (email) => (dispatch, getState, {rest}) => {
@@ -366,8 +371,8 @@ export const requestConfirmEmail = (email) => (dispatch, getState, {rest}) => {
})
.catch((error) => {
console.error(error);
const errorMessage = error.translation_key ? t(`error.${error.translation_key}`) : error.toString();
dispatch(verifyEmailFailure(errorMessage));
dispatch(verifyEmailFailure(error));
throw error;
});
};
@@ -53,3 +53,4 @@ export const UPDATE_USERNAME = 'UPDATE_USERNAME';
export const SET_REQUIRE_EMAIL_VERIFICATION = 'SET_REQUIRE_EMAIL_VERIFICATION';
export const SET_REDIRECT_URI = 'SET_REDIRECT_URI';
export const RESET_SIGNIN_DIALOG = 'RESET_SIGNIN_DIALOG';
@@ -10,7 +10,7 @@ const initialState = {
showCreateUsernameDialog: false,
checkedInitialLogin: false,
view: 'SIGNIN',
error: '',
error: null,
passwordRequestSuccess: null,
passwordRequestFailure: null,
emailVerificationFailure: false,
@@ -45,14 +45,15 @@ export default function auth (state = initialState, action) {
showSignInDialog: true,
signInDialogFocus: true,
};
case actions.HIDE_SIGNIN_DIALOG :
case actions.RESET_SIGNIN_DIALOG:
case actions.HIDE_SIGNIN_DIALOG:
return {
...state,
isLoading: false,
showSignInDialog: false,
signInDialogFocus: false,
view: 'SIGNIN',
error: '',
error: null,
passwordRequestFailure: null,
passwordRequestSuccess: null,
emailVerificationFailure: false,
@@ -74,7 +75,7 @@ export default function auth (state = initialState, action) {
return {
...state,
showCreateUsernameDialog: false,
error: '',
error: null,
};
case actions.CREATE_USERNAME_FAILURE:
return {
@@ -92,6 +93,7 @@ export default function auth (state = initialState, action) {
case actions.FETCH_SIGNIN_REQUEST:
return {
...state,
email: action.email,
isLoading: true,
};
case actions.CHECK_LOGIN_FAILURE:
@@ -120,6 +122,7 @@ export default function auth (state = initialState, action) {
isLoading: false,
error: action.error,
user: null,
view: action.error.translation_key === 'EMAIL_NOT_VERIFIED' ? 'RESEND_VERIFICATION' : state.view,
};
case actions.FETCH_SIGNUP_FACEBOOK_REQUEST:
return {
@@ -175,7 +178,7 @@ export default function auth (state = initialState, action) {
case actions.VALID_FORM:
return {
...state,
error: '',
error: null,
};
case actions.FETCH_FORGOT_PASSWORD_SUCCESS:
return {
@@ -200,7 +203,7 @@ export default function auth (state = initialState, action) {
case actions.VERIFY_EMAIL_FAILURE:
return {
...state,
emailVerificationFailure: true,
emailVerificationFailure: action.error,
emailVerificationLoading: false,
};
case actions.VERIFY_EMAIL_REQUEST:
+2
View File
@@ -194,8 +194,10 @@ en:
NO_SPECIAL_CHARACTERS: "Usernames can contain letters numbers and _ only"
PASSWORD_LENGTH: "Password is too short"
PROFANITY_ERROR: "Usernames must not contain profanity. Please contact the administrator if you believe this to be in error."
RATE_LIMIT_EXCEEDED: "Rate limit exceeded"
USERNAME_IN_USE: "Username already in use"
USERNAME_REQUIRED: "Must input a username"
EMAIL_NOT_VERIFIED: "E-mail address not verified"
EDIT_WINDOW_ENDED: "You can no longer edit this comment. The time window to do so has expired."
EDIT_USERNAME_NOT_AUTHORIZED: "You do not have permission to update your username."
SAME_USERNAME_PROVIDED: "You must submit a different username."
@@ -0,0 +1,15 @@
.header {
margin-bottom: 20px;
text-align: center;
font-size: 1.2em;
}
.notVerified {
padding: 10px;
margin-bottom: 20px;
border-radius: 2px;
border: solid 1px #dddd00;
background: #FFFF9C;
color: #777700;
}
@@ -0,0 +1,43 @@
import React from 'react';
import {Button, Spinner, Success, Alert} from 'plugin-api/beta/client/components/ui';
import PropTypes from 'prop-types';
import styles from './ResendVerification.css';
import t from 'coral-framework/services/i18n';
class ResendVerification extends React.Component {
render() {
const {resendVerification, error, loading, success, email} = this.props;
return (
<div className="talk-resend-verification">
<h1 className={styles.header}>
{t('sign_in.email_verify_cta')}
</h1>
{error &&
<Alert>
{error.translation_key ? t(`error.${error.translation_key}`) : error.toString()}
</Alert>}
<div className={styles.notVerified}>
{t('error.email_not_verified', email)}
</div>
<div>
<Button id="resendConfirmEmail" cStyle="black" onClick={resendVerification} full>
{t('sign_in.request_new_verify_email')}
</Button>
{loading && <Spinner />}
{success && <Success />}
</div>
</div>
);
}
}
ResendVerification.propTypes = {
resendVerification: PropTypes.bool.isRequired,
error: PropTypes.object,
loading: PropTypes.bool,
success: PropTypes.bool,
email: PropTypes.string.isRequired,
};
export default ResendVerification;
@@ -5,13 +5,22 @@ import styles from './styles.css';
import SignInContent from './SignInContent';
import SignUpContent from './SignUpContent';
import ForgotContent from './ForgotContent';
import ResendVerification from './ResendVerification';
const SignDialog = ({open, view, hideSignInDialog, ...props}) => (
const SignDialog = ({open, view, resetSignInDialog, ...props}) => (
<Dialog className={styles.dialog} id="signInDialog" open={open}>
<span className={styles.close} onClick={hideSignInDialog}>×</span>
{view !== 'SIGNIN' && <span className={styles.close} onClick={resetSignInDialog}>×</span>}
{view === 'SIGNIN' && <SignInContent {...props} />}
{view === 'SIGNUP' && <SignUpContent {...props} />}
{view === 'FORGOT' && <ForgotContent {...props} />}
{view === 'RESEND_VERIFICATION' &&
<ResendVerification
resendVerification={props.resendVerification}
error={props.auth.emailVerificationFailure}
success={props.auth.emailVerificationSuccess}
loading={props.auth.emailVerificationLoading}
email={props.auth.email}
/>}
</Dialog>
);
@@ -15,6 +15,7 @@ import {
fetchSignUpFacebook,
fetchForgotPassword,
requestConfirmEmail,
resetSignInDialog,
facebookCallback,
invalidForm,
validForm,
@@ -31,7 +32,6 @@ class SignInContainer extends React.Component {
password: '',
confirmPassword: ''
},
emailToBeResent: '',
errors: {},
showErrors: false
};
@@ -80,26 +80,15 @@ class SignInContainer extends React.Component {
);
};
handleChangeEmail = (e) => {
const {value} = e.target;
this.setState({emailToBeResent: value});
};
handleResendVerification = (e) => {
e.preventDefault();
resendVerification = () => {
this.props
.requestConfirmEmail(
this.state.emailToBeResent,
)
.requestConfirmEmail(this.props.auth.email)
.then(() => {
setTimeout(() => {
// allow success UI to be shown for a second, and then close the modal
this.props.hideSignInDialog();
this.props.resetSignInDialog();
}, 2500);
})
.catch((err) => {
console.error(err);
});
};
@@ -194,6 +183,7 @@ const mapDispatchToProps = (dispatch) =>
requestConfirmEmail,
changeView,
hideSignInDialog,
resetSignInDialog,
invalidForm,
validForm
},
@@ -1,16 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import {Button, TextField, Spinner, Success, Alert} from 'plugin-api/beta/client/components/ui';
import {Button, TextField, Spinner, Alert} from 'plugin-api/beta/client/components/ui';
import styles from './styles.css';
import t from 'coral-framework/services/i18n';
const SignInContent = ({
handleChange,
handleChangeEmail,
emailToBeResent,
handleResendVerification,
emailVerificationLoading,
emailVerificationSuccess,
formData,
changeView,
handleSignIn,
@@ -21,71 +16,56 @@ const SignInContent = ({
<div className="coral-sign-in">
<div className={`${styles.header} header`}>
<h1>
{auth.emailVerificationFailure
? t('sign_in.email_verify_cta')
: t('sign_in.sign_in_to_join')}
{t('sign_in.sign_in_to_join')}
</h1>
</div>
{auth.error && <Alert>{auth.error}</Alert>}
{auth.emailVerificationFailure
? <form onSubmit={handleResendVerification}>
<p>{t('sign_in.request_new_verify_email')}</p>
{auth.error &&
<Alert>
{auth.error.translation_key ? t(`error.${auth.error.translation_key}`) : auth.error.toString()}
</Alert>}
<div>
<div className={`${styles.socialConnections} social-connections`}>
<Button cStyle="facebook" onClick={fetchSignInFacebook} full>
{t('sign_in.facebook_sign_in')}
</Button>
</div>
<div className={styles.separator}>
<h1>
{t('sign_in.or')}
</h1>
</div>
<form onSubmit={handleSignIn}>
<TextField
id="confirm-email"
id="email"
type="email"
label={t('sign_in.email')}
value={emailToBeResent}
onChange={handleChangeEmail}
value={formData.email}
style={{fontSize: 16}}
onChange={handleChange}
/>
<Button id="resendConfirmEmail" type="submit" cStyle="black" full>
Send Email
</Button>
{emailVerificationLoading && <Spinner />}
{emailVerificationSuccess && <Success />}
<TextField
id="password"
type="password"
label={t('sign_in.password')}
value={formData.password}
style={{fontSize: 16}}
onChange={handleChange}
/>
<div className={styles.action}>
{!auth.isLoading
? <Button
id="coralLogInButton"
type="submit"
cStyle="black"
className={styles.signInButton}
full
>
{t('sign_in.sign_in')}
</Button>
: <Spinner />}
</div>
</form>
: <div>
<div className={`${styles.socialConnections} social-connections`}>
<Button cStyle="facebook" onClick={fetchSignInFacebook} full>
{t('sign_in.facebook_sign_in')}
</Button>
</div>
<div className={styles.separator}>
<h1>
{t('sign_in.or')}
</h1>
</div>
<form onSubmit={handleSignIn}>
<TextField
id="email"
type="email"
label={t('sign_in.email')}
value={formData.email}
style={{fontSize: 16}}
onChange={handleChange}
/>
<TextField
id="password"
type="password"
label={t('sign_in.password')}
value={formData.password}
style={{fontSize: 16}}
onChange={handleChange}
/>
<div className={styles.action}>
{!auth.isLoading
? <Button
id="coralLogInButton"
type="submit"
cStyle="black"
className={styles.signInButton}
full
>
{t('sign_in.sign_in')}
</Button>
: <Spinner />}
</div>
</form>
</div>}
</div>
<div className={`${styles.footer} footer`}>
<span>
<a onClick={() => changeView('FORGOT')}>
@@ -111,12 +91,12 @@ SignInContent.propTypes = {
}).isRequired,
fetchSignInFacebook: PropTypes.func.isRequired,
handleSignIn: PropTypes.func.isRequired,
handleChange: PropTypes.func.isRequired,
changeView: PropTypes.func.isRequired,
emailVerificationLoading: PropTypes.bool.isRequired,
emailVerificationSuccess: PropTypes.bool.isRequired,
handleResendVerification: PropTypes.func.isRequired,
handleChangeEmail: PropTypes.func.isRequired,
emailToBeResent: PropTypes.string.isRequired
resendVerification: PropTypes.func.isRequired,
formData: PropTypes.object,
};
export default SignInContent;
@@ -1,7 +1,7 @@
en:
sign_in:
email_verify_cta: "Please verify your email address."
request_new_verify_email: "Request another email:"
request_new_verify_email: "Request another email"
verify_email: "Thank you for creating an account! We sent an email to the address you provided to verify your account."
verify_email2: "You must verify your account before engaging with the community."
not_you: "Not you?"
@@ -45,7 +45,7 @@ en:
es:
sign_in:
email_verify_cta: "Por favor confirme su correo."
request_new_verify_email: "Enviar otro correo:"
request_new_verify_email: "Enviar otro correo"
verify_email: "¡Gracias por crear una cuenta! Le enviamos un correo a la direcció\
n que dio para confirmar su cuenta."
verify_email2: "Debe confirmarla antes de poder involucrarse en la comunidad."
@@ -92,7 +92,7 @@ es:
fr:
sign_in:
email_verify_cta: "Merci de vérifier votre adresse e-mail."
request_new_verify_email: "Demander un nouvel envoi d'e-mail :"
request_new_verify_email: "Demander un nouvel envoi d'e-mail"
verify_email: "Merci d'avoir créé un compte ! Nous avons envoyé un courrier électronique à l'adresse que vous avez fournie pour vérifier votre adresse e-mail."
verify_email2: "Vous devez vérifier votre adresse e-mail avant de vous engager auprès de la communauté."
not_you: "Pas vous ?"