mirror of
https://github.com/wassname/talk.git
synced 2026-07-24 13:20:47 +08:00
More refactoring
This commit is contained in:
@@ -7,4 +7,8 @@ export { default as excludeIf } from './excludeIf';
|
||||
export { default as connect } from './connect';
|
||||
export { default as withMergedSettings } from './withMergedSettings';
|
||||
export { default as withSignIn } from './withSignIn';
|
||||
export { default as withSignUp } from './withSignUp';
|
||||
export { default as withForgotPassword } from './withForgotPassword';
|
||||
export {
|
||||
default as withResendEmailConfirmation,
|
||||
} from './withResendEmailConfirmation';
|
||||
|
||||
@@ -11,6 +11,7 @@ export default hoistStatics(WrappedComponent => {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
rest: PropTypes.func,
|
||||
pym: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -19,9 +20,11 @@ export default hoistStatics(WrappedComponent => {
|
||||
success: false,
|
||||
};
|
||||
|
||||
forgotPassword = email => {
|
||||
forgotPassword = (email, redirectUri) => {
|
||||
if (!redirectUri) {
|
||||
redirectUri = this.context.pym.parentUrl || location.href;
|
||||
}
|
||||
const { rest } = this.context;
|
||||
const redirectUri = location.href;
|
||||
this.setState({ loading: true, error: null, success: false });
|
||||
|
||||
rest('/account/password/reset', {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translateError } from '../utils';
|
||||
|
||||
/**
|
||||
* WithResendEmailConfirmaton provides properties `forgotPasssword`, `loading`, `errorMessage`, `success`.
|
||||
*/
|
||||
export default hoistStatics(WrappedComponent => {
|
||||
class WithResendEmailConfirmaton extends React.Component {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
rest: PropTypes.func,
|
||||
pym: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
success: false,
|
||||
};
|
||||
|
||||
resendEmailConfirmation = (email, redirectUri) => {
|
||||
if (!redirectUri) {
|
||||
redirectUri = this.context.pym.parentUrl || location.href;
|
||||
}
|
||||
const { rest } = this.context;
|
||||
this.setState({ loading: true, error: null, success: false });
|
||||
|
||||
rest('/users/resend-verify', {
|
||||
method: 'POST',
|
||||
body: { email },
|
||||
headers: { 'X-Pym-Url': redirectUri },
|
||||
})
|
||||
.then(() => {
|
||||
this.setState({ loading: false, error: null, success: true });
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
this.setState({ loading: false, error });
|
||||
});
|
||||
};
|
||||
|
||||
getErrorMessage() {
|
||||
if (!this.state.error) {
|
||||
return '';
|
||||
}
|
||||
return translateError(this.state.error);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...this.props}
|
||||
resendEmailConfirmation={this.resendEmailConfirmation}
|
||||
success={this.state.success}
|
||||
loading={this.state.loading}
|
||||
errorMessage={this.getErrorMessage()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return WithResendEmailConfirmaton;
|
||||
});
|
||||
@@ -6,7 +6,13 @@ import { translateError } from '../utils';
|
||||
import { t } from '../services/i18n';
|
||||
|
||||
/**
|
||||
* WithSignIn provides properties `signIn`, `loading`, `errorMessage`, `requireRecaptcha`, 'success'.
|
||||
* WithSignIn provides properties
|
||||
* `signIn`
|
||||
* `loading`
|
||||
* `errorMessage`
|
||||
* `requireRecaptcha`
|
||||
* `requireEmailConfirmation`
|
||||
* 'success'
|
||||
*/
|
||||
export default hoistStatics(WrappedComponent => {
|
||||
class WithSignIn extends React.Component {
|
||||
@@ -20,6 +26,7 @@ export default hoistStatics(WrappedComponent => {
|
||||
loading: false,
|
||||
success: false,
|
||||
requireRecaptcha: false,
|
||||
requireEmailConfirmation: false,
|
||||
};
|
||||
|
||||
signIn = (email, password, recaptchaResponse) => {
|
||||
@@ -51,6 +58,8 @@ export default hoistStatics(WrappedComponent => {
|
||||
if (error.translation_key === 'LOGIN_MAXIMUM_EXCEEDED') {
|
||||
changeSet.requireRecaptcha = !!this.context.store.getState().config
|
||||
.static.TALK_RECAPTCHA_PUBLIC;
|
||||
} else if (error.translation_key === 'EMAIL_NOT_VERIFIED') {
|
||||
changeSet.requireEmailConfirmation = true;
|
||||
}
|
||||
this.setState(changeSet);
|
||||
});
|
||||
@@ -73,6 +82,7 @@ export default hoistStatics(WrappedComponent => {
|
||||
loading={this.state.loading}
|
||||
errorMessage={this.getErrorMessage()}
|
||||
requireRecaptcha={this.state.requireRecaptcha}
|
||||
requireEmailConfirmation={this.state.requireEmailConfirmation}
|
||||
success={this.state.success}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import React from 'react';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translateError } from '../utils';
|
||||
import validate from '../helpers/validate';
|
||||
import errorMsg from 'coral-framework/helpers/error';
|
||||
import t from '../services/i18n';
|
||||
import withQuery from './withQuery';
|
||||
import get from 'lodash/get';
|
||||
|
||||
const requiredFields = ['username', 'email', 'password'];
|
||||
const allFields = requiredFields;
|
||||
|
||||
const QUERY = gql`
|
||||
query TalkFramework_WithSignUpQuery {
|
||||
settings {
|
||||
requireEmailConfirmation
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const withSettingsQuery = withQuery(QUERY);
|
||||
|
||||
/**
|
||||
* withSignUp provides properties `signUp`, `loading`, `errorMessage`, `requireEmailVerification`, 'success', 'validate'.
|
||||
*/
|
||||
const withSignUp = hoistStatics(WrappedComponent => {
|
||||
class WithSignUp extends React.Component {
|
||||
static contextTypes = {
|
||||
store: PropTypes.object,
|
||||
rest: PropTypes.func,
|
||||
pym: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
root: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
success: false,
|
||||
};
|
||||
|
||||
validate = (field, value) => {
|
||||
if (!allFields.includes(field)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (requiredFields.includes(field) && !value) {
|
||||
return t('sign_in.required_field');
|
||||
}
|
||||
|
||||
if (field in validate) {
|
||||
return validate[field](value) ? '' : errorMsg[field];
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
signUp = ({ username, email, password }, redirectUri) => {
|
||||
if (!redirectUri) {
|
||||
redirectUri = this.context.pym.parentUrl || location.href;
|
||||
}
|
||||
|
||||
const { rest } = this.context;
|
||||
const params = {
|
||||
method: 'POST',
|
||||
body: {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
},
|
||||
headers: { 'X-Pym-Url': redirectUri },
|
||||
};
|
||||
|
||||
rest('/users', params)
|
||||
.then(() => {
|
||||
this.setState({ success: true, loading: false, error: null });
|
||||
})
|
||||
.catch(error => {
|
||||
if (!error.status || error.status !== 401) {
|
||||
console.error(error);
|
||||
}
|
||||
const changeSet = { success: false, loading: false, error };
|
||||
this.setState(changeSet);
|
||||
});
|
||||
};
|
||||
|
||||
getErrorMessage() {
|
||||
if (!this.state.error) {
|
||||
return '';
|
||||
}
|
||||
return translateError(this.state.error);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...this.props}
|
||||
signUp={this.signUp}
|
||||
loading={this.state.loading}
|
||||
errorMessage={this.getErrorMessage()}
|
||||
requireEmailConfirmation={
|
||||
!!get(this.props, 'root.settings.requireEmailConfirmation')
|
||||
}
|
||||
success={this.state.success}
|
||||
validate={this.validate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return WithSignUp;
|
||||
});
|
||||
|
||||
export default compose(withSettingsQuery, withSignUp);
|
||||
@@ -5,8 +5,6 @@ import { Button, TextField } from 'plugin-api/beta/client/components/ui';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
class ForgotPassword extends React.Component {
|
||||
state = { value: '' };
|
||||
|
||||
handleSignUpLink = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSignUpLink();
|
||||
|
||||
@@ -3,7 +3,9 @@ import { Dialog } from 'plugin-api/beta/client/components/ui';
|
||||
import styles from './Main.css';
|
||||
import PropTypes from 'prop-types';
|
||||
import SignIn from '../containers/SignIn';
|
||||
import SignUp from '../containers/SignUp';
|
||||
import ForgotPassword from '../containers/ForgotPassword';
|
||||
import ResendEmailConfirmation from '../containers/ResendEmailConfirmation';
|
||||
import * as views from '../enums/views';
|
||||
|
||||
const Main = ({ view, onResetView }) => (
|
||||
@@ -14,7 +16,9 @@ const Main = ({ view, onResetView }) => (
|
||||
</span>
|
||||
)}
|
||||
{view === views.SIGN_IN && <SignIn />}
|
||||
{view === views.SIGN_UP && <SignUp />}
|
||||
{view === views.FORGOT_PASSWORD && <ForgotPassword />}
|
||||
{view === views.RESEND_EMAIL_CONFIRMATION && <ResendEmailConfirmation />}
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
|
||||
@@ -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,56 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Spinner,
|
||||
Success,
|
||||
Alert,
|
||||
} from 'plugin-api/beta/client/components/ui';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './ResendEmailConfirmation.css';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
class ResendVerification extends React.Component {
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { email, errorMessage, loading, success } = this.props;
|
||||
return (
|
||||
<div className="talk-resend-verification">
|
||||
<h1 className={styles.header}>{t('sign_in.email_verify_cta')}</h1>
|
||||
|
||||
{errorMessage && <Alert>{errorMessage}</Alert>}
|
||||
<div className={styles.notVerified}>
|
||||
{t('error.email_not_verified', email)}
|
||||
</div>
|
||||
<div>
|
||||
{!loading &&
|
||||
!success && (
|
||||
<Button
|
||||
id="resendConfirmEmail"
|
||||
cStyle="black"
|
||||
onClick={this.handleSubmit}
|
||||
full
|
||||
>
|
||||
{t('sign_in.request_new_verify_email')}
|
||||
</Button>
|
||||
)}
|
||||
{loading && <Spinner />}
|
||||
{success && <Success />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ResendVerification.propTypes = {
|
||||
success: PropTypes.bool.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default ResendVerification;
|
||||
@@ -0,0 +1,49 @@
|
||||
.header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header h1, .separator h1{
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.socialConnections {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.separator h1{
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.hint {
|
||||
color: grey;
|
||||
font-weight: 600;
|
||||
padding: 3px 0 16px;
|
||||
}
|
||||
|
||||
.action {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.signInButton {
|
||||
margin-top: 10px;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 20px auto 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer span {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #2c69b6;
|
||||
cursor: pointer;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Spinner,
|
||||
Success,
|
||||
Alert,
|
||||
} from 'plugin-api/beta/client/components/ui';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import styles from './SignUp.css';
|
||||
|
||||
class SignUp extends React.Component {
|
||||
handleSignInLink = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSignInLink();
|
||||
};
|
||||
|
||||
handleUsernameChange = e => this.props.onUsernameChange(e.target.value);
|
||||
handleEmailChange = e => this.props.onEmailChange(e.target.value);
|
||||
handlePasswordChange = e => this.props.onPasswordChange(e.target.value);
|
||||
handlePasswordRepeatChange = e =>
|
||||
this.props.onPasswordRepeatChange(e.target.value);
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
this.props.onSubmit();
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
passwordRepeat,
|
||||
usernameError,
|
||||
emailError,
|
||||
passwordError,
|
||||
passwordRepeatError,
|
||||
loading,
|
||||
errorMessage,
|
||||
requireEmailConfirmation,
|
||||
success,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.header}>
|
||||
<h1>{t('sign_in.sign_up')}</h1>
|
||||
</div>
|
||||
|
||||
{errorMessage && <Alert>{errorMessage}</Alert>}
|
||||
{!success && (
|
||||
<div>
|
||||
<div className={styles.socialConnections}>Social</div>
|
||||
<div className={styles.separator}>
|
||||
<h1>{t('sign_in.or')}</h1>
|
||||
</div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<TextField
|
||||
id="email"
|
||||
type="email"
|
||||
label={t('sign_in.email')}
|
||||
value={email}
|
||||
style={{ fontSize: 16 }}
|
||||
showErrors={!!emailError}
|
||||
errorMsg={emailError}
|
||||
onChange={this.handleEmailChange}
|
||||
/>
|
||||
<TextField
|
||||
id="username"
|
||||
type="text"
|
||||
label={t('sign_in.username')}
|
||||
value={username}
|
||||
style={{ fontSize: 16 }}
|
||||
showErrors={!!usernameError}
|
||||
errorMsg={usernameError}
|
||||
onChange={this.handleUsernameChange}
|
||||
/>
|
||||
<TextField
|
||||
id="password"
|
||||
type="password"
|
||||
label={t('sign_in.password')}
|
||||
value={password}
|
||||
style={{ fontSize: 16 }}
|
||||
showErrors={!!passwordError}
|
||||
errorMsg={passwordError}
|
||||
onChange={this.handlePasswordChange}
|
||||
minLength="8"
|
||||
/>
|
||||
{passwordError && (
|
||||
<span className={styles.hint}>
|
||||
{' '}
|
||||
Password must be at least 8 characters.{' '}
|
||||
</span>
|
||||
)}
|
||||
<TextField
|
||||
id="confirmPassword"
|
||||
type="password"
|
||||
label={t('sign_in.confirm_password')}
|
||||
value={passwordRepeat}
|
||||
style={{ fontSize: 16 }}
|
||||
showErrors={!!passwordRepeatError}
|
||||
errorMsg={passwordRepeatError}
|
||||
onChange={this.handlePasswordRepeatChange}
|
||||
minLength="8"
|
||||
/>
|
||||
<div className={styles.action}>
|
||||
<Button
|
||||
type="submit"
|
||||
cStyle="black"
|
||||
id="coralSignUpButton"
|
||||
className={styles.signInButton}
|
||||
full
|
||||
>
|
||||
{t('sign_in.sign_up')}
|
||||
</Button>
|
||||
{loading && <Spinner />}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
{success && (
|
||||
<div>
|
||||
<Success />
|
||||
{requireEmailConfirmation && (
|
||||
<p>
|
||||
{t('sign_in.verify_email')}
|
||||
<br />
|
||||
<br />
|
||||
{t('sign_in.verify_email2')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.footer}>
|
||||
{t('sign_in.already_have_an_account')}{' '}
|
||||
<a id="coralSignInViewTrigger" onClick={this.handleSignInLink}>
|
||||
{t('sign_in.sign_in')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignUp.propTypes = {
|
||||
loading: PropTypes.bool.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
usernameError: PropTypes.string.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
emailError: PropTypes.string.isRequired,
|
||||
password: PropTypes.string.isRequired,
|
||||
passwordError: PropTypes.string.isRequired,
|
||||
passwordRepeat: PropTypes.string.isRequired,
|
||||
passwordRepeatError: PropTypes.string.isRequired,
|
||||
onUsernameChange: PropTypes.func.isRequired,
|
||||
onEmailChange: PropTypes.func.isRequired,
|
||||
onPasswordChange: PropTypes.func.isRequired,
|
||||
onPasswordRepeatChange: PropTypes.func.isRequired,
|
||||
onSignInLink: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
requireEmailConfirmation: PropTypes.bool.isRequired,
|
||||
success: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default SignUp;
|
||||
@@ -11,6 +11,22 @@ class MainContainer extends React.Component {
|
||||
this.props.setView(views.SIGN_IN);
|
||||
};
|
||||
|
||||
resizeHeight() {
|
||||
setTimeout(() => {
|
||||
const height = document.getElementById('signInDialog').offsetHeight + 100;
|
||||
window.resizeTo(500, height);
|
||||
}, 20);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.resizeHeight();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.view !== this.props.view) {
|
||||
this.resizeHeight();
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return <Main onResetView={this.resetView} view={this.props.view} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withResendEmailConfirmation } from 'coral-framework/hocs';
|
||||
import { compose } from 'recompose';
|
||||
import ResendEmailConfirmaton from '../components/ResendEmailConfirmation';
|
||||
import { connect } from 'plugin-api/beta/client/hocs';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as views from '../enums/views';
|
||||
import { setView } from '../actions';
|
||||
|
||||
class ResendEmailConfirmatonContainer extends Component {
|
||||
handleSubmit = () => {
|
||||
this.props.resendEmailConfirmation(this.props.email);
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.success) {
|
||||
setTimeout(() => {
|
||||
// allow success UI to be shown for a second, and then close the modal
|
||||
this.props.setView(views.SIGN_IN);
|
||||
}, 2500);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ResendEmailConfirmaton
|
||||
onSubmit={this.handleSubmit}
|
||||
email={this.props.email}
|
||||
errorMessage={this.props.errorMessage}
|
||||
success={this.props.success}
|
||||
loading={this.props.loading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ResendEmailConfirmatonContainer.propTypes = {
|
||||
success: PropTypes.bool.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
resendEmailConfirmation: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
setView: PropTypes.func.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = ({ talkPluginAuth: state }) => ({
|
||||
email: state.email,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
setView,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withResendEmailConfirmation
|
||||
)(ResendEmailConfirmatonContainer);
|
||||
@@ -34,7 +34,9 @@ class SignInContainer extends Component {
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.success) {
|
||||
if (nextProps.requireEmailConfirmation) {
|
||||
this.props.setView(views.RESEND_EMAIL_CONFIRMATION);
|
||||
} else if (nextProps.success) {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
@@ -47,8 +49,8 @@ class SignInContainer extends Component {
|
||||
onPasswordChange={this.props.setPassword}
|
||||
onForgotPasswordLink={this.handleForgotPasswordLink}
|
||||
onSignUpLink={this.handleSignUpLink}
|
||||
email={this.state.email}
|
||||
password={this.state.password}
|
||||
email={this.props.email}
|
||||
password={this.props.password}
|
||||
errorMessage={this.props.errorMessage}
|
||||
onRecaptchaVerify={this.handleRecaptchaVerify}
|
||||
requireRecaptcha={this.props.requireRecaptcha}
|
||||
@@ -62,6 +64,7 @@ SignInContainer.propTypes = {
|
||||
signIn: PropTypes.func.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
requireRecaptcha: PropTypes.bool.isRequired,
|
||||
requireEmailConfirmation: PropTypes.bool.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
success: PropTypes.bool.isRequired,
|
||||
setView: PropTypes.func.isRequired,
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withSignUp } from 'coral-framework/hocs';
|
||||
import { compose } from 'recompose';
|
||||
import SignUp from '../components/SignUp';
|
||||
import { connect } from 'plugin-api/beta/client/hocs';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as views from '../enums/views';
|
||||
import { setView, setEmail, setPassword } from '../actions';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
class SignUpContainer extends Component {
|
||||
state = {
|
||||
username: '',
|
||||
passwordRepeat: '',
|
||||
usernameError: '',
|
||||
emailError: '',
|
||||
passwordError: '',
|
||||
passwordRepeatError: '',
|
||||
};
|
||||
|
||||
validate = data => {
|
||||
let valid = true;
|
||||
const changes = {};
|
||||
Object.keys(data).forEach(name => {
|
||||
const error = this.props.validate(name, data[name]);
|
||||
if (error) {
|
||||
valid = false;
|
||||
}
|
||||
changes[`${name}Error`] = error;
|
||||
});
|
||||
|
||||
if (data.password !== data.passwordRepeat) {
|
||||
changes['passwordRepeatError'] = t('sign_in.passwords_dont_match');
|
||||
valid = false;
|
||||
}
|
||||
|
||||
this.setState(changes);
|
||||
return valid;
|
||||
};
|
||||
|
||||
handleSubmit = () => {
|
||||
const data = {
|
||||
username: this.state.username,
|
||||
email: this.props.email,
|
||||
password: this.props.password,
|
||||
passwordRepeat: this.state.passwordRepeat,
|
||||
};
|
||||
|
||||
if (this.validate(data)) {
|
||||
this.props.signUp(data);
|
||||
}
|
||||
};
|
||||
|
||||
setUsername = username => this.setState({ username });
|
||||
setPasswordRepeat = passwordRepeat => this.setState({ passwordRepeat });
|
||||
|
||||
handleForgotPasswordLink = () => {
|
||||
this.props.setView(views.FORGOT_PASSWORD);
|
||||
};
|
||||
|
||||
handleSignInLink = () => {
|
||||
this.props.setView(views.SIGN_IN);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SignUp
|
||||
onSubmit={this.handleSubmit}
|
||||
onUsernameChange={this.setUsername}
|
||||
onEmailChange={this.props.setEmail}
|
||||
onPasswordChange={this.props.setPassword}
|
||||
onPasswordRepeatChange={this.setPasswordRepeat}
|
||||
onForgotPasswordLink={this.handleForgotPasswordLink}
|
||||
onSignInLink={this.handleSignInLink}
|
||||
username={this.state.username}
|
||||
email={this.props.email}
|
||||
password={this.props.password}
|
||||
passwordRepeat={this.state.passwordRepeat}
|
||||
errorMessage={this.props.errorMessage}
|
||||
onRecaptchaVerify={this.handleRecaptchaVerify}
|
||||
requireEmailConfirmation={this.props.requireEmailConfirmation}
|
||||
loading={this.props.loading}
|
||||
success={this.props.success}
|
||||
usernameError={this.state.usernameError}
|
||||
emailError={this.state.emailError}
|
||||
passwordError={this.state.passwordError}
|
||||
passwordRepeatError={this.state.passwordRepeatError}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignUpContainer.propTypes = {
|
||||
setView: PropTypes.func.isRequired,
|
||||
email: PropTypes.string.isRequired,
|
||||
password: PropTypes.string.isRequired,
|
||||
setEmail: PropTypes.func.isRequired,
|
||||
setPassword: PropTypes.func.isRequired,
|
||||
signUp: PropTypes.func.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
errorMessage: PropTypes.string.isRequired,
|
||||
requireEmailConfirmation: PropTypes.bool.isRequired,
|
||||
success: PropTypes.bool.isRequired,
|
||||
validate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = ({ talkPluginAuth: state }) => ({
|
||||
email: state.email,
|
||||
password: state.password,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
setView,
|
||||
setEmail,
|
||||
setPassword,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withSignUp
|
||||
)(SignUpContainer);
|
||||
@@ -1,4 +1,4 @@
|
||||
export const SIGN_IN = 'SIGN_IN';
|
||||
export const FORGOT_PASSWORD = 'FORGOT_PASSWORD';
|
||||
export const SIGN_UP = 'SIGN_UP';
|
||||
export const VERIFY_EMAIL = 'VERIFY_EMAIL';
|
||||
export const RESEND_EMAIL_CONFIRMATION = 'RESEND_EMAIL_CONFIRMATION';
|
||||
|
||||
Reference in New Issue
Block a user