mirror of
https://github.com/wassname/talk.git
synced 2026-09-10 12:43:11 +08:00
Merge branch 'master' into gdpr-email
This commit is contained in:
@@ -6,6 +6,7 @@ import Login from './login/containers/Main';
|
||||
import reducer from './login/reducer';
|
||||
import ChangePassword from './profile-settings/containers/ChangePassword';
|
||||
import Profile from './profile-settings/containers/Profile';
|
||||
import ChangeUsername from './profile-settings/containers/ChangeUsername';
|
||||
|
||||
export default {
|
||||
reducer,
|
||||
@@ -14,6 +15,7 @@ export default {
|
||||
stream: [UserBox, SignInButton, SetUsernameDialog],
|
||||
login: [Login],
|
||||
profileHeader: [Profile],
|
||||
profileHeader: [ChangeUsername],
|
||||
profileSettings: [ChangePassword],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
.container {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
color: #202020;
|
||||
padding: 10px;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
|
||||
&.editing {
|
||||
background-color: #EDEDED;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-grow: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.email {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.username {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 1px solid #787d80;
|
||||
background-color: transparent;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
background-color: #3498DB;
|
||||
border-color: #3498DB;
|
||||
color: white;
|
||||
|
||||
> i {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #399ee2;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
border-color: #e0e0e0;
|
||||
|
||||
&:hover {
|
||||
background-color: #e0e0e0;
|
||||
color: #4f5c67;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cancelButton {
|
||||
color:#787D80;
|
||||
margin-top: 6px;
|
||||
font-size: 0.9em;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.detailLabel {
|
||||
border: solid 1px #787D80;
|
||||
border-radius: 2px;
|
||||
background-color: white;
|
||||
height: 30px;
|
||||
display: inline-block;
|
||||
width: 230px;
|
||||
display: flex;
|
||||
|
||||
> .detailLabelIcon {
|
||||
font-size: 1.2em;
|
||||
padding: 0 5px;
|
||||
color: #787D80;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background-color: #E0E0E0;
|
||||
}
|
||||
}
|
||||
|
||||
.detailValue {
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 1em;
|
||||
color: #000;
|
||||
height: 30px;
|
||||
outline: none;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bottomText {
|
||||
color: #474747;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.detailList {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.detailItem {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './ChangeUsername.css';
|
||||
import { Button } from 'plugin-api/beta/client/components/ui';
|
||||
import ChangeUsernameDialog from './ChangeUsernameDialog';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
import InputField from './InputField';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { canUsernameBeUpdated } from 'coral-framework/utils/user';
|
||||
|
||||
const initialState = {
|
||||
editing: false,
|
||||
showDialog: false,
|
||||
formData: {},
|
||||
};
|
||||
|
||||
class ChangeUsername extends React.Component {
|
||||
state = initialState;
|
||||
|
||||
clearForm = () => {
|
||||
this.setState(initialState);
|
||||
};
|
||||
|
||||
enableEditing = () => {
|
||||
this.setState({
|
||||
editing: true,
|
||||
});
|
||||
};
|
||||
|
||||
disableEditing = () => {
|
||||
this.setState({
|
||||
editing: false,
|
||||
});
|
||||
};
|
||||
|
||||
cancel = () => {
|
||||
this.clearForm();
|
||||
this.disableEditing();
|
||||
};
|
||||
|
||||
showDialog = () => {
|
||||
this.setState({
|
||||
showDialog: true,
|
||||
});
|
||||
};
|
||||
|
||||
onSave = async () => {
|
||||
this.showDialog();
|
||||
};
|
||||
|
||||
saveChanges = async () => {
|
||||
const { newUsername } = this.state.formData;
|
||||
const { changeUsername } = this.props;
|
||||
|
||||
try {
|
||||
await changeUsername(newUsername);
|
||||
this.props.notify(
|
||||
'success',
|
||||
t('talk-plugin-auth.change_username.changed_username_success_msg')
|
||||
);
|
||||
} catch (err) {
|
||||
this.props.notify('error', getErrorMessages(err));
|
||||
}
|
||||
|
||||
this.clearForm();
|
||||
this.disableEditing();
|
||||
};
|
||||
|
||||
onChange = e => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
this.setState(state => ({
|
||||
formData: {
|
||||
...state.formData,
|
||||
[name]: value,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
closeDialog = () => {
|
||||
this.setState({
|
||||
showDialog: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
username,
|
||||
emailAddress,
|
||||
root: { me: { state: { status } } },
|
||||
notify,
|
||||
} = this.props;
|
||||
const { editing, formData, showDialog } = this.state;
|
||||
|
||||
return (
|
||||
<section
|
||||
className={cn('talk-plugin-auth--edit-profile', styles.container, {
|
||||
[styles.editing]: editing,
|
||||
})}
|
||||
>
|
||||
<ChangeUsernameDialog
|
||||
canUsernameBeUpdated={canUsernameBeUpdated(status)}
|
||||
showDialog={showDialog}
|
||||
onChange={this.onChange}
|
||||
formData={formData}
|
||||
username={username}
|
||||
closeDialog={this.closeDialog}
|
||||
saveChanges={this.saveChanges}
|
||||
notify={notify}
|
||||
/>
|
||||
|
||||
{editing ? (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.detailList}>
|
||||
<InputField
|
||||
icon="person"
|
||||
id="newUsername"
|
||||
name="newUsername"
|
||||
onChange={this.onChange}
|
||||
defaultValue={username}
|
||||
columnDisplay
|
||||
validationType="username"
|
||||
>
|
||||
<span className={styles.bottomText}>
|
||||
{t('talk-plugin-auth.change_username.change_username_note')}
|
||||
</span>
|
||||
</InputField>
|
||||
<InputField
|
||||
icon="email"
|
||||
id="email"
|
||||
name="email"
|
||||
value={emailAddress}
|
||||
validationType="username"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.content}>
|
||||
<h2 className={styles.username}>{username}</h2>
|
||||
{emailAddress ? (
|
||||
<p className={styles.email}>{emailAddress}</p>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
{editing ? (
|
||||
<div className={styles.actions}>
|
||||
<Button
|
||||
className={cn(styles.button, styles.saveButton)}
|
||||
icon="save"
|
||||
onClick={this.onSave}
|
||||
disabled={
|
||||
!this.state.formData.newUsername ||
|
||||
this.state.formData.newUsername === username
|
||||
}
|
||||
>
|
||||
{t('talk-plugin-auth.change_username.save')}
|
||||
</Button>
|
||||
<a className={styles.cancelButton} onClick={this.cancel}>
|
||||
{t('talk-plugin-auth.change_username.cancel')}
|
||||
</a>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.actions}>
|
||||
<Button
|
||||
className={styles.button}
|
||||
icon="settings"
|
||||
onClick={this.enableEditing}
|
||||
>
|
||||
{t('talk-plugin-auth.change_username.edit_profile')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChangeUsername.propTypes = {
|
||||
root: PropTypes.object.isRequired,
|
||||
changeUsername: PropTypes.func.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
username: PropTypes.string,
|
||||
emailAddress: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ChangeUsername;
|
||||
@@ -0,0 +1,84 @@
|
||||
.dialog {
|
||||
border: none;
|
||||
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
|
||||
width: 320px;
|
||||
top: 10px;
|
||||
font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 20px;
|
||||
line-height: 14px;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: #363636;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #6b6b6b;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.3em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1em;
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
color: #4C4C4D;
|
||||
font-size: 1em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.bottomNote {
|
||||
font-size: 0.9em;
|
||||
line-height: 20px;
|
||||
padding-top: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bottomActions {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.usernamesChange {
|
||||
margin: 18px 0;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
border: 1px solid #787d80;
|
||||
background-color: transparent;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
line-height: normal;
|
||||
|
||||
&:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmChanges {
|
||||
background-color: #3498DB;
|
||||
border-color: #3498DB;
|
||||
color: white;
|
||||
height: 30px;
|
||||
font-size: 0.9em;
|
||||
|
||||
&:hover {
|
||||
background-color: #3ba3ec;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cn from 'classnames';
|
||||
import styles from './ChangeUsernameDialog.css';
|
||||
import InputField from './InputField';
|
||||
import { Button, Dialog } from 'plugin-api/beta/client/components/ui';
|
||||
import { t } from 'plugin-api/beta/client/services';
|
||||
|
||||
class ChangeUsernameDialog extends React.Component {
|
||||
state = {
|
||||
showError: false,
|
||||
};
|
||||
|
||||
showError = () => {
|
||||
this.setState({
|
||||
showError: true,
|
||||
});
|
||||
};
|
||||
|
||||
confirmChanges = async () => {
|
||||
if (this.formHasError()) {
|
||||
this.showError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.props.canUsernameBeUpdated) {
|
||||
this.props.notify(
|
||||
'error',
|
||||
t('talk-plugin-auth.change_username.change_username_attempt')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.props.saveChanges();
|
||||
this.props.closeDialog();
|
||||
};
|
||||
|
||||
formHasError = () =>
|
||||
this.props.formData.confirmNewUsername !== this.props.formData.newUsername;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Dialog
|
||||
open={this.props.showDialog}
|
||||
className={cn(styles.dialog, 'talk-plugin-auth--edit-profile-dialog')}
|
||||
>
|
||||
<span className={styles.close} onClick={this.props.closeDialog}>
|
||||
×
|
||||
</span>
|
||||
<h1 className={styles.title}>
|
||||
{t('talk-plugin-auth.change_username.confirm_username_change')}
|
||||
</h1>
|
||||
<div className={styles.content}>
|
||||
<p className={styles.description}>
|
||||
{t('talk-plugin-auth.change_username.description')}
|
||||
</p>
|
||||
<div className={styles.usernamesChange}>
|
||||
<span className={styles.item}>
|
||||
{t('talk-plugin-auth.change_username.old_username')}:{' '}
|
||||
{this.props.username}
|
||||
</span>
|
||||
<span className={styles.item}>
|
||||
{t('talk-plugin-auth.change_username.new_username')}:{' '}
|
||||
{this.props.formData.newUsername}
|
||||
</span>
|
||||
</div>
|
||||
<form>
|
||||
<InputField
|
||||
id="confirmNewUsername"
|
||||
label="Re-enter new username"
|
||||
name="confirmNewUsername"
|
||||
type="text"
|
||||
onChange={this.props.onChange}
|
||||
defaultValue=""
|
||||
hasError={this.formHasError() && this.state.showError}
|
||||
errorMsg={t(
|
||||
'talk-plugin-auth.change_username.username_does_not_match'
|
||||
)}
|
||||
showError={this.state.showError}
|
||||
columnDisplay
|
||||
showSuccess={false}
|
||||
validationType="username"
|
||||
>
|
||||
<span className={styles.bottomNote}>
|
||||
{t('talk-plugin-auth.change_username.bottom_note')}
|
||||
</span>
|
||||
</InputField>
|
||||
</form>
|
||||
<div className={styles.bottomActions}>
|
||||
<Button className={styles.cancel}>
|
||||
{t('talk-plugin-auth.change_username.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.confirmChanges}
|
||||
onClick={this.confirmChanges}
|
||||
>
|
||||
{t('talk-plugin-auth.change_username.confirm_changes')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChangeUsernameDialog.propTypes = {
|
||||
saveChanges: PropTypes.func,
|
||||
closeDialog: PropTypes.func,
|
||||
showDialog: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
username: PropTypes.string,
|
||||
formData: PropTypes.object,
|
||||
canUsernameBeUpdated: PropTypes.bool.isRequired,
|
||||
notify: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ChangeUsernameDialog;
|
||||
@@ -0,0 +1,12 @@
|
||||
import { compose } from 'react-apollo';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'plugin-api/beta/client/hocs';
|
||||
import ChangeUsername from '../components/ChangeUsername';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { withChangeUsername } from 'plugin-api/beta/client/hocs';
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
|
||||
|
||||
export default compose(connect(null, mapDispatchToProps), withChangeUsername)(
|
||||
ChangeUsername
|
||||
);
|
||||
@@ -165,8 +165,9 @@ en:
|
||||
incorrect_password: "Incorrect Password"
|
||||
confirm_change: "Confirm Change"
|
||||
cancel: "Cancel"
|
||||
change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications"
|
||||
change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications."
|
||||
changed_username_success_msg: "Username Changed - Your username has been successfully changed. You will not be able to change your user name for 14 days."
|
||||
change_username_attempt: "Username can't be updated. Usernames can only be changed every 14 days."
|
||||
de:
|
||||
talk-plugin-auth:
|
||||
login:
|
||||
|
||||
Reference in New Issue
Block a user