More refactoring

This commit is contained in:
Chi Vinh Le
2018-02-09 23:18:21 +01:00
parent f4fc8915e3
commit 4b6a3b5b9d
17 changed files with 352 additions and 28 deletions
@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import styles from './ForgotPassword.css';
import { Button, TextField, Alert, Success } from 'coral-ui';
import t from 'coral-framework/services/i18n';
class ForgotPassword extends React.Component {
constructor(props) {
@@ -23,8 +24,7 @@ class ForgotPassword extends React.Component {
renderSuccess() {
return (
<div className={styles.success} onClick={this.handleSignInLink}>
If you have a registered account, a password reset link was sent to that
email.{' '}
{t('password_reset.mail_sent')}{' '}
<a
className={styles.signInLink}
href="#"
@@ -7,7 +7,6 @@ import ForgotPassword from '../components/ForgotPassword';
class ForgotPasswordContainer extends Component {
state = {
email: '',
password: '',
};
handleSubmit = () => {
+1
View File
@@ -23,6 +23,7 @@ en:
click_to_confirm: "Click below to confirm your email address"
confirm: "Confirm"
password_reset:
mail_sent: 'If you have a registered account, a password reset link was sent to that email'
set_new_password: "Change Your Password"
new_password: "New Password"
new_password_help: "Password must be at least 8 characters"
+2
View File
@@ -2,8 +2,10 @@ import UserBox from './stream/containers/UserBox';
import SignInButton from './stream/containers/SignInButton';
import translations from './translations.yml';
import Login from './login/containers/Main';
import reducer from './login/reducer';
export default {
reducer,
translations,
slots: {
stream: [UserBox, SignInButton],
@@ -0,0 +1,16 @@
import * as actions from './constants';
export const setView = view => ({
type: actions.SET_VIEW,
view,
});
export const setEmail = email => ({
type: actions.SET_EMAIL,
email,
});
export const setPassword = password => ({
type: actions.SET_PASSWORD,
password,
});
@@ -0,0 +1,42 @@
.header {
margin-bottom: 20px;
}
.header h1, .separator h1{
text-align: center;
font-size: 1.2em;
}
.button {
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;
}
.success {
border: 1px solid green;
background-color: lightgreen;
padding: 10px;
}
.failure {
border: 1px solid orange;
background-color: 1px solid coral;
padding: 10px;
}
@@ -0,0 +1,79 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './ForgotPassword.css';
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();
};
handleSignInLink = e => {
e.preventDefault();
this.props.onSignInLink();
};
handleEmailChange = e => this.props.onEmailChange(e.target.value);
handleSubmit = e => {
e.preventDefault();
this.props.onSubmit();
};
render() {
const { email, errorMessage, success } = this.props;
return (
<div>
<div className={styles.header}>
<h1>{t('sign_in.recover_password')}</h1>
</div>
<form onSubmit={this.handleSubmit}>
<div className={styles.textField}>
<TextField
type="email"
style={{ fontSize: 16 }}
id="email"
name="email"
label={t('sign_in.email')}
onChange={this.handleEmailChange}
value={email}
/>
</div>
<Button type="submit" cStyle="black" className={styles.button} full>
{t('sign_in.recover_password')}
</Button>
{success ? (
<p className={styles.success}>{t('password_reset.mail_sent')} </p>
) : null}
{errorMessage ? (
<p className={styles.failure}>{errorMessage}</p>
) : null}
</form>
<div className={styles.footer}>
<span>
{t('sign_in.need_an_account')}{' '}
<a onClick={this.handleSignUpLink}>{t('sign_in.register')}</a>
</span>
<span>
{t('sign_in.already_have_an_account')}{' '}
<a onClick={this.handleSignInLink}>{t('sign_in.sign_in')}</a>
</span>
</div>
</div>
);
}
}
ForgotPassword.propTypes = {
success: PropTypes.bool.isRequired,
email: PropTypes.string.isRequired,
onEmailChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired,
onSignInLink: PropTypes.func.isRequired,
onSignUpLink: PropTypes.func.isRequired,
};
export default ForgotPassword;
@@ -6,3 +6,19 @@
font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif;
font-size: 14px;
}
.close {
font-size: 20px;
line-height: 14px;
top: 10px;
right: 10px;
position: absolute;
display: block;
font-weight: bold;
color: #363636;
cursor: pointer;
}
.close:hover {
color: #6b6b6b;
}
@@ -1,13 +1,26 @@
import React from 'react';
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 ForgotPassword from '../containers/ForgotPassword';
import * as views from '../enums/views';
const SignDialog = () => (
const Main = ({ view, onResetView }) => (
<Dialog className={styles.dialog} id="signInDialog" open={true}>
<SignIn />
{view !== views.SIGN_IN && (
<span className={styles.close} onClick={onResetView}>
×
</span>
)}
{view === views.SIGN_IN && <SignIn />}
{view === views.FORGOT_PASSWORD && <ForgotPassword />}
</Dialog>
);
export default SignDialog;
Main.propTypes = {
view: PropTypes.string.isRequired,
onResetView: PropTypes.func.isRequired,
};
export default Main;
@@ -18,9 +18,9 @@ class SignIn extends React.Component {
e.preventDefault();
this.props.onForgotPasswordLink();
};
handleRegisterLink = e => {
handleSignUpLink = e => {
e.preventDefault();
this.props.onRegisterLink();
this.props.onSignUpLink();
};
handleEmailChange = e => this.props.onEmailChange(e.target.value);
handlePasswordChange = e => this.props.onPasswordChange(e.target.value);
@@ -113,7 +113,7 @@ class SignIn extends React.Component {
</span>
<span>
{t('sign_in.need_an_account')}
<a onClick={this.handleRegisterLink} id="coralRegister">
<a onClick={this.handleSignUpLink} id="coralRegister">
{t('sign_in.register')}
</a>
</span>
@@ -130,7 +130,7 @@ SignIn.propTypes = {
onEmailChange: PropTypes.func.isRequired,
onPasswordChange: PropTypes.func.isRequired,
onForgotPasswordLink: PropTypes.func.isRequired,
onRegisterLink: PropTypes.func.isRequired,
onSignUpLink: PropTypes.func.isRequired,
onRecaptchaVerify: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired,
@@ -0,0 +1,5 @@
const prefix = 'TALK_AUTH';
export const SET_VIEW = `${prefix}_SET_VIEW`;
export const SET_EMAIL = `${prefix}_SET_EMAIL`;
export const SET_PASSWORD = `${prefix}_SET_PASSWORD`;
@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withForgotPassword } from 'coral-framework/hocs';
import { compose } from 'recompose';
import ForgotPassword from '../components/ForgotPassword';
import { connect } from 'plugin-api/beta/client/hocs';
import { bindActionCreators } from 'redux';
import * as views from '../enums/views';
import { setView, setEmail } from '../actions';
class ForgotPasswordContainer extends Component {
handleSubmit = () => {
this.props.forgotPassword(this.props.email);
};
handleSignUpLink = () => {
this.props.setView(views.SIGN_UP);
};
handleSignInLink = () => {
this.props.setView(views.SIGN_IN);
};
render() {
return (
<ForgotPassword
onSubmit={this.handleSubmit}
onEmailChange={this.props.setEmail}
email={this.props.email}
errorMessage={this.props.errorMessage}
success={this.props.success}
onSignInLink={this.handleSignInLink}
onSignUpLink={this.handleSignUpLink}
/>
);
}
}
ForgotPasswordContainer.propTypes = {
success: PropTypes.bool.isRequired,
forgotPassword: PropTypes.func.isRequired,
errorMessage: PropTypes.string.isRequired,
setView: PropTypes.func.isRequired,
email: PropTypes.string.isRequired,
setEmail: PropTypes.func.isRequired,
};
const mapStateToProps = ({ talkPluginAuth: state }) => ({
email: state.email,
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
setView,
setEmail,
},
dispatch
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withForgotPassword
)(ForgotPasswordContainer);
@@ -1,10 +1,36 @@
import React from 'react';
import PropTypes from 'prop-types';
import Main from '../components/Main';
import { connect } from 'plugin-api/beta/client/hocs';
import { bindActionCreators } from 'redux';
import { setView } from '../actions';
import * as views from '../enums/views';
class MainContainer extends React.Component {
resetView = () => {
this.props.setView(views.SIGN_IN);
};
render() {
return <Main />;
return <Main onResetView={this.resetView} view={this.props.view} />;
}
}
export default MainContainer;
MainContainer.propTypes = {
view: PropTypes.string.isRequired,
setView: PropTypes.func.isRequired,
};
const mapStateToProps = ({ talkPluginAuth: state }) => ({
view: state.view,
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
setView,
},
dispatch
);
export default connect(mapStateToProps, mapDispatchToProps)(MainContainer);
@@ -3,34 +3,36 @@ import PropTypes from 'prop-types';
import { withSignIn } from 'coral-framework/hocs';
import { compose } from 'recompose';
import SignIn from '../components/SignIn';
import { connect } from 'plugin-api/beta/client/hocs';
import { bindActionCreators } from 'redux';
import * as views from '../enums/views';
import { setView, setEmail, setPassword } from '../actions';
class SignInContainer extends Component {
state = {
email: '',
password: '',
recaptchaResponse: '',
};
handleSubmit = () => {
this.props.signIn(
this.state.email,
this.state.password,
this.props.email,
this.props.password,
this.state.recaptchaResponse
);
};
handleEmailChange = email => {
this.setState({ email });
};
handlePasswordChange = password => {
this.setState({ password });
};
handleRecaptchaVerify = recaptchaResponse => {
this.setState({ recaptchaResponse });
};
handleForgotPasswordLink = () => {
this.props.setView(views.FORGOT_PASSWORD);
};
handleSignUpLink = () => {
this.props.setView(views.SIGN_UP);
};
componentWillReceiveProps(nextProps) {
if (nextProps.success) {
window.close();
@@ -41,8 +43,10 @@ class SignInContainer extends Component {
return (
<SignIn
onSubmit={this.handleSubmit}
onEmailChange={this.handleEmailChange}
onPasswordChange={this.handlePasswordChange}
onEmailChange={this.props.setEmail}
onPasswordChange={this.props.setPassword}
onForgotPasswordLink={this.handleForgotPasswordLink}
onSignUpLink={this.handleSignUpLink}
email={this.state.email}
password={this.state.password}
errorMessage={this.props.errorMessage}
@@ -60,6 +64,29 @@ SignInContainer.propTypes = {
requireRecaptcha: PropTypes.bool.isRequired,
loading: PropTypes.bool.isRequired,
success: PropTypes.bool.isRequired,
setView: PropTypes.func.isRequired,
email: PropTypes.string.isRequired,
password: PropTypes.string.isRequired,
setEmail: PropTypes.func.isRequired,
setPassword: PropTypes.func.isRequired,
};
export default compose(withSignIn)(SignInContainer);
const mapStateToProps = ({ talkPluginAuth: state }) => ({
email: state.email,
password: state.password,
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
setView,
setEmail,
setPassword,
},
dispatch
);
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withSignIn
)(SignInContainer);
@@ -0,0 +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';
@@ -0,0 +1,30 @@
import * as actions from './constants';
import * as views from './enums/views';
const initialState = {
view: views.SIGN_IN,
email: '',
password: '',
};
export default function reducer(state = initialState, action) {
switch (action.type) {
case actions.SET_VIEW:
return {
...state,
view: action.view,
};
case actions.SET_EMAIL:
return {
...state,
email: action.email,
};
case actions.SET_PASSWORD:
return {
...state,
password: action.password,
};
default:
return state;
}
}