diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index a4256848e..6dffeae42 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -50,7 +50,7 @@ "configure": { "enable-pre-moderation": "Enable pre-moderation", "enable-pre-moderation-text": "Moderators must approve any comment before it is published.", - "require-email-verification": "Require Email Confirmation", + "require-email-verification": "Require Email Verification", "require-email-verification-text": "New Users must verify their email before commenting", "include-comment-stream": "Include Comment Stream Description for Readers.", "include-comment-stream-desc": "Write a message to be added to the top of your comment stream. Pose a topic, include community guidelines, etc.", diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index fce2f14fa..a853efead 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -138,7 +138,7 @@ class Embed extends Component { :

{asset.settings.closedMessage}

} - {!loggedIn && } + {!loggedIn && } {loggedIn && user && } ({type: actions.CLEAN_STATE}); const signInRequest = () => ({type: actions.FETCH_SIGNIN_REQUEST}); const signInSuccess = (user, isAdmin) => ({type: actions.FETCH_SIGNIN_SUCCESS, user, isAdmin}); const signInFailure = error => ({type: actions.FETCH_SIGNIN_FAILURE, error}); -const emailConfirmError = () => ({type: actions.EMAIL_CONFIRM_ERROR}); export const fetchSignIn = (formData) => (dispatch) => { dispatch(signInRequest()); @@ -58,7 +57,6 @@ export const fetchSignIn = (formData) => (dispatch) => { // the user might not have a valid email. prompt the user user re-request the confirmation email dispatch(signInFailure(lang.t('error.emailNotVerified', error.metadata))); - dispatch(emailConfirmError()); } else { // invalid credentials @@ -117,15 +115,12 @@ const signUpRequest = () => ({type: actions.FETCH_SIGNUP_REQUEST}); const signUpSuccess = user => ({type: actions.FETCH_SIGNUP_SUCCESS, user}); const signUpFailure = error => ({type: actions.FETCH_SIGNUP_FAILURE, error}); -export const fetchSignUp = formData => (dispatch) => { +export const fetchSignUp = (formData, redirectUri) => (dispatch) => { dispatch(signUpRequest()); - coralApi('/users', {method: 'POST', body: formData}) + coralApi('/users', {method: 'POST', body: formData, headers: {'X-Pym-Url': redirectUri}}) .then(({user}) => { dispatch(signUpSuccess(user)); - setTimeout(() =>{ - dispatch(changeView('SIGNIN')); - }, 3000); }) .catch(error => { dispatch(signUpFailure(lang.t(`error.${error.message}`))); @@ -186,20 +181,20 @@ export const checkLogin = () => dispatch => { }); }; -const confirmEmailRequest = () => ({type: actions.CONFIRM_EMAIL_REQUEST}); -const confirmEmailSuccess = () => ({type: actions.CONFIRM_EMAIL_SUCCESS}); -const confirmEmailFailure = () => ({type: actions.CONFIRM_EMAIL_FAILURE}); +const verifyEmailRequest = () => ({type: actions.VERIFY_EMAIL_REQUEST}); +const verifyEmailSuccess = () => ({type: actions.VERIFY_EMAIL_SUCCESS}); +const verifyEmailFailure = () => ({type: actions.VERIFY_EMAIL_FAILURE}); -export const requestConfirmEmail = email => dispatch => { - dispatch(confirmEmailRequest()); - return coralApi('/users/resend-confirm', {method: 'POST', body: {email}}) +export const requestConfirmEmail = (email, redirectUri) => dispatch => { + dispatch(verifyEmailRequest()); + return coralApi('/users/resend-verify', {method: 'POST', body: {email}, headers: {'X-Pym-Url': redirectUri}}) .then(() => { - dispatch(confirmEmailSuccess()); + dispatch(verifyEmailSuccess()); }) .catch(err => { - console.log('failed to send email confirmation', err); + console.log('failed to send email verification', err); - // email might have already been confirmed - dispatch(confirmEmailFailure()); + // email might have already been verifyed + dispatch(verifyEmailFailure()); }); }; diff --git a/client/coral-framework/constants/auth.js b/client/coral-framework/constants/auth.js index 2b5f762c1..b6ad3d3a1 100644 --- a/client/coral-framework/constants/auth.js +++ b/client/coral-framework/constants/auth.js @@ -41,8 +41,7 @@ export const CHECK_LOGIN_FAILURE = 'CHECK_LOGIN_FAILURE'; export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN'; +export const VERIFY_EMAIL_REQUEST = 'VERIFY_EMAIL_REQUEST'; +export const VERIFY_EMAIL_SUCCESS = 'VERIFY_EMAIL_SUCCESS'; +export const VERIFY_EMAIL_FAILURE = 'VERIFY_EMAIL_FAILURE'; export const UPDATE_DISPLAYNAME = 'UPDATE_DISPLAYNAME'; -export const EMAIL_CONFIRM_ERROR = 'EMAIL_CONFIRM_ERROR'; -export const CONFIRM_EMAIL_REQUEST = 'CONFIRM_EMAIL_REQUEST'; -export const CONFIRM_EMAIL_SUCCESS = 'CONFIRM_EMAIL_SUCCESS'; -export const CONFIRM_EMAIL_FAILURE = 'CONFIRM_EMAIL_FAILURE'; diff --git a/client/coral-framework/helpers/response.js b/client/coral-framework/helpers/response.js index d95773c04..64803faef 100644 --- a/client/coral-framework/helpers/response.js +++ b/client/coral-framework/helpers/response.js @@ -14,7 +14,8 @@ const buildOptions = (inputOptions = {}) => { _csrf: csurfDOM ? csurfDOM.content : false }; - const options = Object.assign({}, defaultOptions, inputOptions); + let options = Object.assign({}, defaultOptions, inputOptions); + options.headers = Object.assign({}, defaultOptions.headers, inputOptions.headers); if (options._csrf) { switch (options.method.toLowerCase()) { diff --git a/client/coral-framework/reducers/auth.js b/client/coral-framework/reducers/auth.js index a8606c0cc..c894ecde4 100644 --- a/client/coral-framework/reducers/auth.js +++ b/client/coral-framework/reducers/auth.js @@ -12,9 +12,9 @@ const initialState = Map({ error: '', passwordRequestSuccess: null, passwordRequestFailure: null, - emailConfirmationFailure: false, - emailConfirmationLoading: false, - emailConfirmationSuccess: false, + emailVerificationFailure: false, + emailVerificationLoading: false, + emailVerificationSuccess: false, successSignUp: false, fromSignUp: false }); @@ -38,9 +38,9 @@ export default function auth (state = initialState, action) { error: '', passwordRequestFailure: null, passwordRequestSuccess: null, - emailConfirmationFailure: false, - emailConfirmationSuccess: false, - emailConfirmationLoading: false, + emailVerificationFailure: false, + emailVerificationSuccess: false, + emailVerificationLoading: false, successSignUp: false })); case actions.SHOW_CREATEDISPLAYNAME_DIALOG : @@ -134,16 +134,16 @@ export default function auth (state = initialState, action) { console.log('Action', action); return state .setIn(['user', 'displayName'], action.displayName); - case actions.EMAIL_CONFIRM_ERROR: + case actions.VERIFY_EMAIL_FAILURE: return state - .set('emailConfirmationFailure', true) - .set('emailConfirmationLoading', false); - case actions.CONFIRM_EMAIL_REQUEST: - return state.set('emailConfirmationLoading', true); - case actions.CONFIRM_EMAIL_SUCCESS: + .set('emailVerificationFailure', true) + .set('emailVerificationLoading', false); + case actions.VERIFY_EMAIL_REQUEST: + return state.set('emailVerificationLoading', true); + case actions.VERIFY_EMAIL_SUCCESS: return state - .set('emailConfirmationSuccess', true) - .set('emailConfirmationLoading', false); + .set('emailVerificationSuccess', true) + .set('emailVerificationLoading', false); default : return state; } diff --git a/client/coral-sign-in/components/SignDialog.js b/client/coral-sign-in/components/SignDialog.js index 0645f110f..6243472b4 100644 --- a/client/coral-sign-in/components/SignDialog.js +++ b/client/coral-sign-in/components/SignDialog.js @@ -17,12 +17,7 @@ const SignDialog = ({open, view, handleClose, offset, ...props}) => ( }}> × {view === 'SIGNIN' && } - { - view === 'SIGNUP' && - } + {view === 'SIGNUP' && } {view === 'FORGOT' && } ); diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index e27185b52..c7a5dc80d 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -10,35 +10,28 @@ const SignInContent = ({ handleChange, handleChangeEmail, emailToBeResent, - handleResendConfirmation, - emailConfirmationLoading, - emailConfirmationSuccess, + handleResendVerification, + emailVerificationLoading, + emailVerificationSuccess, formData, - ...props + changeView, + handleSignIn, + auth, + fetchSignInFacebook }) => { return (

- {props.auth.emailConfirmationFailure ? lang.t('signIn.emailConfirmCTA') : lang.t('signIn.signIn')} + {auth.emailVerificationFailure ? lang.t('signIn.emailVerifyCTA') : lang.t('signIn.signIn')}

-
- -
-
-

- {lang.t('signIn.or')} -

-
- { props.auth.error && {props.auth.error} } + { auth.error && {auth.error} } { - props.auth.emailConfirmationFailure - ?
-

{lang.t('signIn.requestNewConfirmEmail')}

+ auth.emailVerificationFailure + ? +

{lang.t('signIn.requestNewVerifyEmail')}

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

+ {lang.t('signIn.or')} +

+
+
+ + +
+ { + !auth.isLoading ? + + : + + } +
+ +
}
- props.changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')} + changeView('FORGOT')}>{lang.t('signIn.forgotYourPass')} {lang.t('signIn.needAnAccount')} - props.changeView('SIGNUP')} id='coralRegister'> + changeView('SIGNUP')} id='coralRegister'> {lang.t('signIn.register')} @@ -90,9 +95,17 @@ const SignInContent = ({ }; SignInContent.propTypes = { - emailConfirmationLoading: PropTypes.bool.isRequired, - emailConfirmationSuccess: PropTypes.bool.isRequired, - handleResendConfirmation: PropTypes.func.isRequired, + auth: PropTypes.shape({ + isLoading: PropTypes.bool.isRequired, + error: PropTypes.object, + emailVerificationFailure: PropTypes.bool + }).isRequired, + fetchSignInFacebook: PropTypes.func.isRequired, + handleSignIn: 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 }; diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 80a6fcde4..03c083070 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import Alert from './Alert'; import {Button, FormField, Spinner, Success} from 'coral-ui'; import styles from './styles.css'; @@ -6,83 +6,148 @@ import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); -const SignUpContent = ({handleChange, formData, ...props}) => ( -
-
-

- {lang.t('signIn.signUp')} -

-
-
- -
-
-

- {lang.t('signIn.or')} -

-
- { props.auth.error && {props.auth.error} } -
- - - - { props.errors.password && Password must be at least 8 characters. } - -
- { !props.auth.isLoading && !props.auth.successSignUp && ( - - )} - { props.auth.isLoading && } - { !props.auth.isLoading && props.auth.successSignUp && } + +
+ + { auth.error && {auth.error} } + { beforeSignup && +
+
+ +
+
+

+ {lang.t('signIn.or')} +

+
+ + + + + { errors.password && Password must be at least 8 characters. } + +
+ + { auth.isLoading && } +
+ +
+ } + { + successfulSignup && +
+ + { + emailVerificationEnabled && +

{lang.t('signIn.verifyEmail')}

{lang.t('signIn.verifyEmail2')}

+ } +
+ } +
+ + {lang.t('signIn.alreadyHaveAnAccount')} + changeView('SIGNIN')}> + {lang.t('signIn.signIn')} + + +
- -
- - {lang.t('signIn.alreadyHaveAnAccount')} - props.changeView('SIGNIN')}> - {lang.t('signIn.signIn')} - - -
-
-); + ); + } +} export default SignUpContent; diff --git a/client/coral-sign-in/containers/SignInContainer.js b/client/coral-sign-in/containers/SignInContainer.js index 937c830c9..c92fe024d 100644 --- a/client/coral-sign-in/containers/SignInContainer.js +++ b/client/coral-sign-in/containers/SignInContainer.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {Component, PropTypes} from 'react'; import {connect} from 'react-redux'; import SignDialog from '../components/SignDialog'; import Button from 'coral-ui/components/Button'; @@ -6,6 +6,7 @@ import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; +import {pym} from 'coral-framework'; const lang = new I18n(translations); import { @@ -42,12 +43,16 @@ class SignInContainer extends Component { this.state = this.initialState; this.handleChange = this.handleChange.bind(this); this.handleChangeEmail = this.handleChangeEmail.bind(this); - this.handleResendConfirmation = this.handleResendConfirmation.bind(this); + this.handleResendVerification = this.handleResendVerification.bind(this); this.handleSignUp = this.handleSignUp.bind(this); this.handleSignIn = this.handleSignIn.bind(this); this.addError = this.addError.bind(this); } + static propTypes = { + requireEmailConfirmation: PropTypes.bool.isRequired + } + componentWillMount () { this.props.checkLogin(); } @@ -80,9 +85,9 @@ class SignInContainer extends Component { this.setState({emailToBeResent: value}); } - handleResendConfirmation(e) { + handleResendVerification(e) { e.preventDefault(); - this.props.requestConfirmEmail(this.state.emailToBeResent) + this.props.requestConfirmEmail(this.state.emailToBeResent, pym.parentUrl || location.href) .then(() => { setTimeout(() => { @@ -133,7 +138,7 @@ class SignInContainer extends Component { const {fetchSignUp, validForm, invalidForm} = this.props; this.displayErrors(); if (this.isCompleted() && !Object.keys(errors).length) { - fetchSignUp(this.state.formData); + fetchSignUp(this.state.formData, pym.parentUrl || location.href); validForm(); } else { invalidForm(lang.t('signIn.checkTheForm')); @@ -146,8 +151,9 @@ class SignInContainer extends Component { } render() { - const {auth, showSignInDialog, noButton, offset} = this.props; - const {emailConfirmationLoading, emailConfirmationSuccess} = auth; + const {auth, showSignInDialog, noButton, offset, requireEmailConfirmation} = this.props; + const {emailVerificationLoading, emailVerificationSuccess} = auth; + return (
{!noButton &&