diff --git a/client/coral-embed-stream/src/actions/auth.js b/client/coral-embed-stream/src/actions/auth.js index b96d6f459..22d46a768 100644 --- a/client/coral-embed-stream/src/actions/auth.js +++ b/client/coral-embed-stream/src/actions/auth.js @@ -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; }); }; diff --git a/client/coral-embed-stream/src/constants/auth.js b/client/coral-embed-stream/src/constants/auth.js index 324f75f44..bb2ea6c15 100644 --- a/client/coral-embed-stream/src/constants/auth.js +++ b/client/coral-embed-stream/src/constants/auth.js @@ -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'; diff --git a/client/coral-embed-stream/src/reducers/auth.js b/client/coral-embed-stream/src/reducers/auth.js index 1e18ddffa..679e8d858 100644 --- a/client/coral-embed-stream/src/reducers/auth.js +++ b/client/coral-embed-stream/src/reducers/auth.js @@ -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: diff --git a/locales/en.yml b/locales/en.yml index 2d560fedc..76a434dfc 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -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." diff --git a/plugins/talk-plugin-auth/client/components/ResendVerification.css b/plugins/talk-plugin-auth/client/components/ResendVerification.css new file mode 100644 index 000000000..dc59a9ff1 --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/ResendVerification.css @@ -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; +} + diff --git a/plugins/talk-plugin-auth/client/components/ResendVerification.js b/plugins/talk-plugin-auth/client/components/ResendVerification.js new file mode 100644 index 000000000..b345577a9 --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/ResendVerification.js @@ -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 ( +
+

+ {t('sign_in.email_verify_cta')} +

+ + {error && + + {error.translation_key ? t(`error.${error.translation_key}`) : error.toString()} + } +
+ {t('error.email_not_verified', email)} +
+
+ + {loading && } + {success && } +
+
+ ); + } +} + +ResendVerification.propTypes = { + resendVerification: PropTypes.bool.isRequired, + error: PropTypes.object, + loading: PropTypes.bool, + success: PropTypes.bool, + email: PropTypes.string.isRequired, +}; + +export default ResendVerification; diff --git a/plugins/talk-plugin-auth/client/components/SignDialog.js b/plugins/talk-plugin-auth/client/components/SignDialog.js index 542f53f98..652148d75 100644 --- a/plugins/talk-plugin-auth/client/components/SignDialog.js +++ b/plugins/talk-plugin-auth/client/components/SignDialog.js @@ -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}) => ( - × + {view !== 'SIGNIN' && ×} {view === 'SIGNIN' && } {view === 'SIGNUP' && } {view === 'FORGOT' && } + {view === 'RESEND_VERIFICATION' && + } ); diff --git a/plugins/talk-plugin-auth/client/components/SignInContainer.js b/plugins/talk-plugin-auth/client/components/SignInContainer.js index 011ce45f1..c22ad72c4 100644 --- a/plugins/talk-plugin-auth/client/components/SignInContainer.js +++ b/plugins/talk-plugin-auth/client/components/SignInContainer.js @@ -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 }, diff --git a/plugins/talk-plugin-auth/client/components/SignInContent.js b/plugins/talk-plugin-auth/client/components/SignInContent.js index d1b4caec1..956176b32 100644 --- a/plugins/talk-plugin-auth/client/components/SignInContent.js +++ b/plugins/talk-plugin-auth/client/components/SignInContent.js @@ -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 = ({

- {auth.emailVerificationFailure - ? t('sign_in.email_verify_cta') - : t('sign_in.sign_in_to_join')} + {t('sign_in.sign_in_to_join')}

- {auth.error && {auth.error}} - {auth.emailVerificationFailure - ?
-

{t('sign_in.request_new_verify_email')}

+ {auth.error && + + {auth.error.translation_key ? t(`error.${auth.error.translation_key}`) : auth.error.toString()} + } +
+
+ +
+
+

+ {t('sign_in.or')} +

+
+ - - {emailVerificationLoading && } - {emailVerificationSuccess && } + +
+ {!auth.isLoading + ? + : } +
- :
-
- -
-
-

- {t('sign_in.or')} -

-
-
- - -
- {!auth.isLoading - ? - : } -
- -
} +
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; diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index 189c3d9da..f410ec2d3 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -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 ?"