Refactor talk-plugin-auth part 1

This commit is contained in:
Chi Vinh Le
2018-02-09 20:12:02 +01:00
parent 1774f98519
commit f4fc8915e3
36 changed files with 413 additions and 955 deletions
@@ -0,0 +1,83 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './styles.css';
import {
Dialog,
Alert,
TextField,
Button,
} from 'plugin-api/beta/client/components/ui';
import { FakeComment } from './FakeComment';
import t from 'coral-framework/services/i18n';
const SetUsernameDialog = ({
open,
handleClose,
formData,
handleSubmitUsername,
handleChange,
...props
}) => (
<Dialog
className={styles.dialogusername}
id="createUsernameDialog"
open={open}
>
<span className={styles.close} onClick={handleClose}>
×
</span>
<div>
<div className={styles.header}>
<h1>{t('createdisplay.write_your_username')}</h1>
</div>
<div>
<p className={styles.yourusername}>
{t('createdisplay.your_username')}
</p>
<FakeComment
className={styles.fakeComment}
username={formData.username}
created_at={new Date().toISOString()}
body={t('createdisplay.fake_comment_body')}
/>
<p className={styles.ifyoudont}>
{t('createdisplay.if_you_dont_change_your_name')}
</p>
{props.auth.error && <Alert>{props.auth.error}</Alert>}
<form id="saveUsername" onSubmit={handleSubmitUsername}>
{props.errors.username && (
<span className={styles.hint}>
{' '}
{t('createdisplay.special_characters')}{' '}
</span>
)}
<div className={styles.saveusername}>
<TextField
id="username"
style={{ fontSize: 16 }}
type="string"
label={t('createdisplay.username')}
value={formData.username}
onChange={handleChange}
/>
<Button id="save" type="submit" className={styles.saveButton}>
{t('createdisplay.save')}
</Button>
</div>
</form>
</div>
</div>
</Dialog>
);
SetUsernameDialog.propTypes = {
open: PropTypes.bool,
handleClose: PropTypes.func,
formData: PropTypes.object,
handleSubmitUsername: PropTypes.func,
handleChange: PropTypes.func,
auth: PropTypes.object,
errors: PropTypes.object,
};
export default SetUsernameDialog;
@@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'plugin-api/beta/client/components/ui';
import t from 'coral-framework/services/i18n';
const SignInButton = ({ currentUser, showSignInDialog }) => (
<div className="talk-stream-auth-sign-in-button">
{!currentUser ? (
<Button id="coralSignInButton" onClick={showSignInDialog} full>
{t('sign_in.sign_in_to_comment')}
</Button>
) : null}
</div>
);
SignInButton.propTypes = {
currentUser: PropTypes.object,
showSignInDialog: PropTypes.func,
};
export default SignInButton;
@@ -0,0 +1,21 @@
.userBox {
margin: 10px 0 20px;
letter-spacing: 0.1px;
}
.userBoxLoggedIn {
font-weight: bold;
}
.userBox a {
color: black;
font-weight: bold;
cursor: pointer;
margin: 0px;
margin-left: 4px;
padding-bottom: 2px;
}
.userBox .logout {
border-bottom: solid 1px black;
}
@@ -0,0 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './UserBox.css';
import t from 'coral-framework/services/i18n';
import cn from 'classnames';
const UserBox = ({ user, logout, onShowProfile }) => (
<div>
{user ? (
<div className={cn(styles.userBox, 'talk-stream-auth-userbox')}>
<span className={styles.userBoxLoggedIn}>
{t('sign_in.logged_in_as')}
</span>
<a onClick={onShowProfile}>{user.username}</a>. {t('sign_in.not_you')}
<a
className={cn(styles.logout, 'talk-stream-userbox-logout')}
onClick={() => logout()}
>
{t('sign_in.logout')}
</a>
</div>
) : null}
</div>
);
UserBox.propTypes = {
user: PropTypes.object,
logout: PropTypes.func,
onShowProfile: PropTypes.func,
};
export default UserBox;
@@ -0,0 +1,183 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose } from 'react-apollo';
import { bindActionCreators } from 'redux';
import errorMsj from 'coral-framework/helpers/error';
import validate from 'coral-framework/helpers/validate';
import CreateUsernameDialog from './CreateUsernameDialog';
import { withSetUsername } from 'coral-framework/graphql/mutations';
import { forEachError } from 'plugin-api/beta/client/utils';
import t from 'coral-framework/services/i18n';
import {
showCreateUsernameDialog,
hideCreateUsernameDialog,
invalidForm,
validForm,
updateUsername,
} from 'coral-embed-stream/src/actions/login';
class SetUsernameDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
formData: {
username: (props.auth.user && props.auth.user.username) || '',
},
errors: {},
showErrors: false,
};
}
componentWillReceiveProps(next) {
if (
!this.props.auth.showCreateUsernameDialog &&
next.auth.showCreateUsernameDialog
) {
this.setState({
formData: {
username:
(this.props.auth.user && this.props.auth.user.username) || '',
},
});
}
}
handleChange = e => {
const { name, value } = e.target;
this.setState(
state => ({
...state,
formData: {
...state.formData,
[name]: value,
},
}),
() => {
this.validation(name, value);
}
);
};
addError = (name, error) => {
return this.setState(state => ({
errors: {
...state.errors,
[name]: error,
},
}));
};
validation = (name, value) => {
const { addError } = this;
if (!value.length) {
addError(name, t('createdisplay.required_field'));
} else if (!validate[name](value)) {
addError(name, errorMsj[name]);
} else {
const {[name]: prop, ...errors} = this.state.errors; // eslint-disable-line
// Removes Error
this.setState(state => ({ ...state, errors }));
}
};
isCompleted = () => {
const { formData } = this.state;
return !Object.keys(formData).filter(prop => !formData[prop].length).length;
};
displayErrors = (show = true) => {
this.setState({ showErrors: show });
};
async setUsernameAndClose(username, props = this.props) {
const {
validForm,
invalidForm,
setUsername,
hideCreateUsernameDialog,
updateUsername,
} = props;
try {
// Perform mutation
await setUsername(this.props.auth.user.id, username);
// Also change in redux store...
updateUsername(username);
hideCreateUsernameDialog();
validForm();
} catch (error) {
const msgs = [];
forEachError(error, ({ msg }) => msgs.push(msg));
invalidForm(t(msgs.join(', ')));
}
}
handleSubmitUsername = e => {
e.preventDefault();
const { errors, formData: { username } } = this.state;
const { invalidForm } = this.props;
this.displayErrors();
if (this.isCompleted() && !Object.keys(errors).length) {
this.setUsernameAndClose(username);
} else {
invalidForm(t('createdisplay.check_the_form'));
}
};
handleClose = () => {
this.setUsernameAndClose(this.props.auth.user.username);
};
render() {
const { loggedIn, auth } = this.props;
return (
<div>
<CreateUsernameDialog
open={auth.showCreateUsernameDialog}
handleClose={this.handleClose}
loggedIn={loggedIn}
handleSubmitUsername={this.handleSubmitUsername}
{...this}
{...this.state}
{...this.props}
/>
</div>
);
}
}
SetUsernameDialog.propTypes = {
auth: PropTypes.object,
hideCreateUsernameDialog: PropTypes.func,
validForm: PropTypes.func,
invalidForm: PropTypes.func,
loggedIn: PropTypes.bool,
changeUsername: PropTypes.func,
};
const mapStateToProps = ({ auth }) => ({
auth: auth,
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
showCreateUsernameDialog,
hideCreateUsernameDialog,
invalidForm,
validForm,
updateUsername,
},
dispatch
);
export default compose(
withSetUsername,
connect(mapStateToProps, mapDispatchToProps)
)(SetUsernameDialog);
@@ -0,0 +1,13 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { showSignInDialog } from 'coral-embed-stream/src/actions/login';
import SignInButton from '../components//SignInButton';
const mapStateToProps = ({ auth }) => ({
currentUser: auth.user,
});
const mapDispatchToProps = dispatch =>
bindActionCreators({ showSignInDialog }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(SignInButton);
@@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { logout } from 'coral-framework/actions/auth';
import UserBox from '../components/UserBox';
const mapStateToProps = ({ auth }) => ({
user: auth.user,
});
const mapDispatchToProps = dispatch => bindActionCreators({ logout }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(UserBox);