mirror of
https://github.com/elyby/accounts-frontend.git
synced 2025-02-05 00:19:48 +05:30
#41: implemented ui for change email form
This commit is contained in:
parent
cc967c2c81
commit
a75110fb2e
@ -58,6 +58,7 @@ export default class Profile extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProfileField
|
<ProfileField
|
||||||
|
link="/profile/change-email"
|
||||||
label={'E-mail'}
|
label={'E-mail'}
|
||||||
value={user.email}
|
value={user.email}
|
||||||
/>
|
/>
|
||||||
|
241
src/components/profile/changeEmail/ChangeEmail.jsx
Normal file
241
src/components/profile/changeEmail/ChangeEmail.jsx
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import Helmet from 'react-helmet';
|
||||||
|
import { Motion, spring } from 'react-motion';
|
||||||
|
|
||||||
|
import { Input, Button, Form, FormModel } from 'components/ui/form';
|
||||||
|
import styles from 'components/profile/profileForm.scss';
|
||||||
|
import helpLinks from 'components/auth/helpLinks.scss';
|
||||||
|
import MeasureHeight from 'components/MeasureHeight';
|
||||||
|
|
||||||
|
import changeEmail from './changeEmail.scss';
|
||||||
|
import messages from './ChangeEmail.messages';
|
||||||
|
|
||||||
|
const STEPS_TOTAL = 3;
|
||||||
|
|
||||||
|
// TODO: disable code field, if the code was passed through url
|
||||||
|
|
||||||
|
export default class ChangeEmail extends Component {
|
||||||
|
static displayName = 'ChangeEmail';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
email: PropTypes.string.isRequired,
|
||||||
|
form: PropTypes.instanceOf(FormModel),
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onSubmit: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
static get defaultProps() {
|
||||||
|
return {
|
||||||
|
form: new FormModel()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
activeStep: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {form} = this.props;
|
||||||
|
const {activeStep} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form onSubmit={this.onFormSubmit}
|
||||||
|
form={form}
|
||||||
|
>
|
||||||
|
<div className={styles.contentWithBackButton}>
|
||||||
|
<Link className={styles.backButton} to="/" />
|
||||||
|
|
||||||
|
<div className={styles.form}>
|
||||||
|
<div className={styles.formBody}>
|
||||||
|
<Message {...messages.changeEmailTitle}>
|
||||||
|
{(pageTitle) => (
|
||||||
|
<h3 className={styles.violetTitle}>
|
||||||
|
<Helmet title={pageTitle} />
|
||||||
|
{pageTitle}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
|
</Message>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.changeEmailDescription} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={changeEmail.steps}>
|
||||||
|
{(new Array(STEPS_TOTAL)).fill(0).map((_, step) => (
|
||||||
|
<div className={classNames(changeEmail.step, {
|
||||||
|
[changeEmail.activeStep]: step <= activeStep
|
||||||
|
})} key={step} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.form}>
|
||||||
|
{this.renderStepForms()}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
color="violet"
|
||||||
|
block
|
||||||
|
label={this.isLastStep() ? messages.changeEmailButton : messages.sendEmailButton}
|
||||||
|
onClick={this.onSwitchStep}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={helpLinks.helpLinks}>
|
||||||
|
{this.isLastStep() ? null : (
|
||||||
|
<a href="#" onClick={this.onSwitchStep}>
|
||||||
|
<Message {...messages.alreadyReceivedCode} />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStepForms() {
|
||||||
|
const {form, email} = this.props;
|
||||||
|
const {activeStep} = this.state;
|
||||||
|
|
||||||
|
const activeStepHeight = this.state[`step${activeStep}Height`] || 0;
|
||||||
|
|
||||||
|
// a hack to disable height animation on first render
|
||||||
|
const isHeightMeasured = this.isHeightMeasured;
|
||||||
|
this.isHeightMeasured = activeStepHeight > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Motion
|
||||||
|
style={{
|
||||||
|
transform: spring(activeStep * 100, {stiffness: 500, damping: 50, precision: 0.5}),
|
||||||
|
height: isHeightMeasured ? spring(activeStepHeight, {stiffness: 500, damping: 20, precision: 0.5}) : activeStepHeight
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(interpolatingStyle) => (
|
||||||
|
<div style={{
|
||||||
|
overflow: 'hidden',
|
||||||
|
height: `${interpolatingStyle.height}px`
|
||||||
|
}}>
|
||||||
|
<div className={changeEmail.stepForms} style={{
|
||||||
|
WebkitTransform: `translateX(-${interpolatingStyle.transform}%)`,
|
||||||
|
transform: `translateX(-${interpolatingStyle.transform}%)`
|
||||||
|
}}>
|
||||||
|
<MeasureHeight className={changeEmail.stepForm} onMeasure={this.onStepMeasure(0)}>
|
||||||
|
<div className={styles.formBody}>
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.currentAccountEmail} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<h2 className={changeEmail.currentAccountEmail}>
|
||||||
|
{email}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.pressButtonToStart} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MeasureHeight>
|
||||||
|
|
||||||
|
<MeasureHeight className={changeEmail.stepForm} onMeasure={this.onStepMeasure(1)}>
|
||||||
|
<div className={styles.formBody}>
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.enterInitializationCode} values={{
|
||||||
|
email: (<b>{email}</b>)
|
||||||
|
}} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<Input {...form.bindField('initializationCode')}
|
||||||
|
required
|
||||||
|
skin="light"
|
||||||
|
placeholder={messages.codePlaceholder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.enterNewEmail} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<Input {...form.bindField('newEmail')}
|
||||||
|
required
|
||||||
|
skin="light"
|
||||||
|
placeholder={messages.newEmailPlaceholder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MeasureHeight>
|
||||||
|
|
||||||
|
<MeasureHeight className={changeEmail.stepForm} onMeasure={this.onStepMeasure(2)}>
|
||||||
|
<div className={styles.formBody}>
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<p className={styles.description}>
|
||||||
|
<Message {...messages.enterFinalizationCode} values={{
|
||||||
|
email: (<b>{form.value('newEmail')}</b>)
|
||||||
|
}} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.formRow}>
|
||||||
|
<Input {...form.bindField('finalizationCode')}
|
||||||
|
required
|
||||||
|
skin="light"
|
||||||
|
placeholder={messages.codePlaceholder}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MeasureHeight>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Motion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStepMeasure(step) {
|
||||||
|
return (height) => this.setState({
|
||||||
|
[`step${step}Height`]: height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSwitchStep = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const {activeStep} = this.state;
|
||||||
|
const nextStep = activeStep + 1;
|
||||||
|
|
||||||
|
if (nextStep < STEPS_TOTAL) {
|
||||||
|
this.setState({
|
||||||
|
activeStep: nextStep
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
isLastStep() {
|
||||||
|
return this.state.activeStep + 1 === STEPS_TOTAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUsernameChange = (event) => {
|
||||||
|
this.props.onChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
onFormSubmit = () => {
|
||||||
|
this.props.onSubmit(this.props.form);
|
||||||
|
};
|
||||||
|
}
|
66
src/components/profile/changeEmail/ChangeEmail.messages.js
Normal file
66
src/components/profile/changeEmail/ChangeEmail.messages.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
|
export default defineMessages({
|
||||||
|
changeEmailTitle: {
|
||||||
|
id: 'changeEmailTitle',
|
||||||
|
defaultMessage: 'Change E-mail'
|
||||||
|
// defaultMessage: 'Смена E-mail'
|
||||||
|
},
|
||||||
|
changeEmailDescription: {
|
||||||
|
id: 'changeEmailDescription',
|
||||||
|
defaultMessage: 'To change current account E-mail you must first verify that you own the current address and then confirm the new one.'
|
||||||
|
// defaultMessage: 'Для смены E-mail адреса аккаунта сперва необходимо подтвердить владение текущим адресом, а за тем привязать новый.'
|
||||||
|
},
|
||||||
|
currentAccountEmail: {
|
||||||
|
id: 'currentAccountEmail',
|
||||||
|
defaultMessage: 'Current account E-mail address:'
|
||||||
|
// defaultMessage: 'Текущий E-mail адрес, привязанный к аккаунту:'
|
||||||
|
},
|
||||||
|
pressButtonToStart: {
|
||||||
|
id: 'pressButtonToStart',
|
||||||
|
defaultMessage: 'Press the button below to send a message with the code for E-mail change initialization.'
|
||||||
|
// defaultMessage: 'Нажмите кнопку ниже, что бы отправить письмо с кодом для инциализации процесса смены E-mail адреса.'
|
||||||
|
},
|
||||||
|
enterInitializationCode: {
|
||||||
|
id: 'enterInitializationCode',
|
||||||
|
defaultMessage: 'The E-mail with an initialization code for E-mail change procedure was sent to {email}. Please enter the code into the field below:'
|
||||||
|
// defaultMessage: 'На E-mail {email} было отправлено письмо с кодом для инициализации смены E-mail адреса. Введите его в поле ниже:'
|
||||||
|
},
|
||||||
|
//
|
||||||
|
enterNewEmail: {
|
||||||
|
id: 'enterNewEmail',
|
||||||
|
defaultMessage: 'Then provide your new E-mail address, that you want to use with this account. You will be mailed with confirmation code.'
|
||||||
|
// defaultMessage: 'За тем укажите новый E-mail адрес, к котором хотите привязать свой аккаунт. На него будет выслан код с подтверждением.'
|
||||||
|
},
|
||||||
|
enterFinalizationCode: {
|
||||||
|
id: 'enterFinalizationCode',
|
||||||
|
defaultMessage: 'The E-mail change confirmation code was sent to {email}. Please enter the code received into the field below:'
|
||||||
|
// defaultMessage: 'На указанный E-mail {email} было выслано письмо с кодом для завершщения смены E-mail адреса. Введите полученный код в поле ниже:'
|
||||||
|
},
|
||||||
|
//
|
||||||
|
newEmailPlaceholder: {
|
||||||
|
id: 'newEmailPlaceholder',
|
||||||
|
defaultMessage: 'Enter new E-mail'
|
||||||
|
// defaultMessage: 'Введите новый E-mail'
|
||||||
|
},
|
||||||
|
codePlaceholder: {
|
||||||
|
id: 'codePlaceholder',
|
||||||
|
defaultMessage: 'Paste the code here'
|
||||||
|
// defaultMessage: 'Вставьте код сюда'
|
||||||
|
},
|
||||||
|
sendEmailButton: {
|
||||||
|
id: 'sendEmailButton',
|
||||||
|
defaultMessage: 'Send E-mail'
|
||||||
|
// defaultMessage: 'Отправить E-mail'
|
||||||
|
},
|
||||||
|
changeEmailButton: {
|
||||||
|
id: 'changeEmailButton',
|
||||||
|
defaultMessage: 'Change E-mail'
|
||||||
|
// defaultMessage: 'Сменить E-mail'
|
||||||
|
},
|
||||||
|
alreadyReceivedCode: {
|
||||||
|
id: 'alreadyReceivedCode',
|
||||||
|
defaultMessage: 'Already received code'
|
||||||
|
// defaultMessage: 'Я получил код'
|
||||||
|
}
|
||||||
|
});
|
80
src/components/profile/changeEmail/changeEmail.scss
Normal file
80
src/components/profile/changeEmail/changeEmail.scss
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
@import '~components/ui/colors.scss';
|
||||||
|
|
||||||
|
.steps {
|
||||||
|
width: 35%;
|
||||||
|
margin: 0 auto;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step {
|
||||||
|
position: relative;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
height: 4px;
|
||||||
|
background: #d8d5ce;
|
||||||
|
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
height: 4px;
|
||||||
|
left: 0;
|
||||||
|
right: 100%;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -2px;
|
||||||
|
|
||||||
|
background: #aaa;
|
||||||
|
transition: 0.4s ease 0.1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: -7px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 100%;
|
||||||
|
|
||||||
|
background: #aaa;
|
||||||
|
transition: background 0.4s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeStep {
|
||||||
|
&:before {
|
||||||
|
right: 0;
|
||||||
|
transition-delay: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background: $violet;
|
||||||
|
transition-delay: 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.currentAccountEmail {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.stepForms {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepForm {
|
||||||
|
display: inline-block;
|
||||||
|
white-space: normal;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
@ -5,8 +5,8 @@ import { Link } from 'react-router';
|
|||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
|
|
||||||
import { Input, Button, Form, FormModel } from 'components/ui/form';
|
import { Input, Button, Form, FormModel } from 'components/ui/form';
|
||||||
|
|
||||||
import styles from 'components/profile/profileForm.scss';
|
import styles from 'components/profile/profileForm.scss';
|
||||||
|
|
||||||
import messages from './ChangeUsername.messages';
|
import messages from './ChangeUsername.messages';
|
||||||
|
|
||||||
export default class ChangeUsername extends Component {
|
export default class ChangeUsername extends Component {
|
||||||
|
@ -61,6 +61,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.violetTitle {
|
||||||
|
composes: title;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background: $violet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.description {
|
.description {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
@include button-theme('orange', $orange);
|
@include button-theme('orange', $orange);
|
||||||
@include button-theme('darkBlue', $dark_blue);
|
@include button-theme('darkBlue', $dark_blue);
|
||||||
@include button-theme('lightViolet', $light_violet);
|
@include button-theme('lightViolet', $light_violet);
|
||||||
|
@include button-theme('violet', $violet);
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -17,7 +17,7 @@ export default class Button extends FormComponent {
|
|||||||
PropTypes.string
|
PropTypes.string
|
||||||
]).isRequired,
|
]).isRequired,
|
||||||
block: PropTypes.bool,
|
block: PropTypes.bool,
|
||||||
color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue'])
|
color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue', 'violet'])
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -15,6 +15,8 @@ export default class FormModel {
|
|||||||
* @return {Object} ref and name props for component
|
* @return {Object} ref and name props for component
|
||||||
*/
|
*/
|
||||||
bindField(name) {
|
bindField(name) {
|
||||||
|
this.fields[name] = {};
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
name,
|
name,
|
||||||
ref: (el) => {
|
ref: (el) => {
|
||||||
@ -42,11 +44,17 @@ export default class FormModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
value(fieldId) {
|
value(fieldId) {
|
||||||
if (!this.fields[fieldId]) {
|
const field = this.fields[fieldId];
|
||||||
|
|
||||||
|
if (!field) {
|
||||||
throw new Error(`The field with an id ${fieldId} does not exists`);
|
throw new Error(`The field with an id ${fieldId} does not exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fields[fieldId].getValue();
|
if (!field.getValue) {
|
||||||
|
return ''; // the field was not initialized through ref yet
|
||||||
|
}
|
||||||
|
|
||||||
|
return field.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
setErrors(errors) {
|
setErrors(errors) {
|
||||||
|
@ -66,11 +66,6 @@
|
|||||||
|
|
||||||
transition: border-color .25s;
|
transition: border-color .25s;
|
||||||
|
|
||||||
&::placeholder {
|
|
||||||
opacity: 1;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
&,
|
&,
|
||||||
~ .textFieldIcon {
|
~ .textFieldIcon {
|
||||||
@ -107,6 +102,11 @@
|
|||||||
.darkTextField {
|
.darkTextField {
|
||||||
background: $black;
|
background: $black;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
&,
|
&,
|
||||||
~ .textFieldIcon {
|
~ .textFieldIcon {
|
||||||
border-color: lighter($black);
|
border-color: lighter($black);
|
||||||
@ -116,6 +116,11 @@
|
|||||||
.lightTextField {
|
.lightTextField {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
opacity: 1;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
&,
|
&,
|
||||||
~ .textFieldIcon {
|
~ .textFieldIcon {
|
||||||
border-color: #dcd8cd;
|
border-color: #dcd8cd;
|
||||||
|
@ -42,7 +42,6 @@ class ChangeUsernamePage extends Component {
|
|||||||
|
|
||||||
onSubmit = () => {
|
onSubmit = () => {
|
||||||
this.props.changeUsername(this.form).then(() => {
|
this.props.changeUsername(this.form).then(() => {
|
||||||
console.log('update to', this.props.username)
|
|
||||||
this.setState({
|
this.setState({
|
||||||
actualUsername: this.props.username
|
actualUsername: this.props.username
|
||||||
});
|
});
|
||||||
|
104
src/pages/profile/ProfileChangeEmailPage.jsx
Normal file
104
src/pages/profile/ProfileChangeEmailPage.jsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
|
import accounts from 'services/api/accounts';
|
||||||
|
import { FormModel } from 'components/ui/form';
|
||||||
|
import ChangeEmail from 'components/profile/changeEmail/ChangeEmail';
|
||||||
|
import PasswordRequestForm from 'components/profile/passwordRequestForm/PasswordRequestForm';
|
||||||
|
|
||||||
|
class ProfileChangeEmailPage extends Component {
|
||||||
|
static displayName = 'ProfileChangeEmailPage';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
email: PropTypes.string.isRequired,
|
||||||
|
updateUsername: PropTypes.func.isRequired, // updates username in state
|
||||||
|
changeUsername: PropTypes.func.isRequired // saves username to backend
|
||||||
|
};
|
||||||
|
|
||||||
|
form = new FormModel();
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ChangeEmail form={this.form}
|
||||||
|
onSubmit={this.onSubmit}
|
||||||
|
onChange={this.onUsernameChange}
|
||||||
|
email={this.props.email}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUsernameChange = (username) => {
|
||||||
|
this.props.updateUsername(username);
|
||||||
|
};
|
||||||
|
|
||||||
|
onSubmit = () => {
|
||||||
|
this.props.changeUsername(this.form).then(() => {
|
||||||
|
this.setState({
|
||||||
|
actualUsername: this.props.username
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { routeActions } from 'react-router-redux';
|
||||||
|
import { register as registerPopup, create as createPopup } from 'components/ui/popup/actions';
|
||||||
|
import { updateUser } from 'components/user/actions';
|
||||||
|
|
||||||
|
function goToProfile() {
|
||||||
|
return routeActions.push('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect((state) => ({
|
||||||
|
email: state.user.email
|
||||||
|
}), {
|
||||||
|
updateUsername: (username) => {
|
||||||
|
return updateUser({username});
|
||||||
|
},
|
||||||
|
changeUsername: (form) => {
|
||||||
|
return (dispatch) => accounts.changeUsername(form.serialize())
|
||||||
|
.catch((resp) => {
|
||||||
|
// prevalidate user input, because requestPassword popup will block the
|
||||||
|
// entire form from input, so it must be valid
|
||||||
|
if (resp.errors) {
|
||||||
|
Reflect.deleteProperty(resp.errors, 'password');
|
||||||
|
|
||||||
|
if (Object.keys(resp.errors).length) {
|
||||||
|
form.setErrors(resp.errors);
|
||||||
|
return Promise.reject(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// TODO: судя по всему registerPopup было явно лишним. Надо еще раз
|
||||||
|
// обдумать API и переписать
|
||||||
|
dispatch(registerPopup('requestPassword', PasswordRequestForm));
|
||||||
|
dispatch(createPopup('requestPassword', (props) => ({
|
||||||
|
form,
|
||||||
|
onSubmit: () => {
|
||||||
|
// TODO: hide this logic in action
|
||||||
|
accounts.changeUsername(form.serialize())
|
||||||
|
.catch((resp) => {
|
||||||
|
if (resp.errors) {
|
||||||
|
form.setErrors(resp.errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(resp);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
dispatch(updateUser({
|
||||||
|
username: form.value('username')
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.then(resolve)
|
||||||
|
.then(props.onClose)
|
||||||
|
.then(() => dispatch(goToProfile()));
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
})(ProfileChangeEmailPage);
|
@ -8,6 +8,7 @@ import AuthPage from 'pages/auth/AuthPage';
|
|||||||
import ProfilePage from 'pages/profile/ProfilePage';
|
import ProfilePage from 'pages/profile/ProfilePage';
|
||||||
import ProfileChangePasswordPage from 'pages/profile/ChangePasswordPage';
|
import ProfileChangePasswordPage from 'pages/profile/ChangePasswordPage';
|
||||||
import ProfileChangeUsernamePage from 'pages/profile/ChangeUsernamePage';
|
import ProfileChangeUsernamePage from 'pages/profile/ChangeUsernamePage';
|
||||||
|
import ProfileChangeEmailPage from 'pages/profile/ProfileChangeEmailPage';
|
||||||
|
|
||||||
import { authenticate } from 'components/user/actions';
|
import { authenticate } from 'components/user/actions';
|
||||||
|
|
||||||
@ -57,6 +58,7 @@ export default function routesFactory(store) {
|
|||||||
<Route path="profile" component={ProfilePage}>
|
<Route path="profile" component={ProfilePage}>
|
||||||
<Route path="change-password" component={ProfileChangePasswordPage} />
|
<Route path="change-password" component={ProfileChangePasswordPage} />
|
||||||
<Route path="change-username" component={ProfileChangeUsernamePage} />
|
<Route path="change-username" component={ProfileChangeUsernamePage} />
|
||||||
|
<Route path="change-email" component={ProfileChangeEmailPage} />
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user