mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-10-03 00:37:18 +05:30
Merge remote-tracking branch 'origin/master' into finish-page
This commit is contained in:
commit
1119354226
@ -18,11 +18,11 @@
|
|||||||
"history": "^1.17.0",
|
"history": "^1.17.0",
|
||||||
"intl-format-cache": "^2.0.4",
|
"intl-format-cache": "^2.0.4",
|
||||||
"intl-messageformat": "^1.1.0",
|
"intl-messageformat": "^1.1.0",
|
||||||
"react": "^0.14.0",
|
"react": "^15.0.0-rc.1",
|
||||||
"react-dom": "^0.14.3",
|
"react-dom": "^15.0.0-rc.1",
|
||||||
"react-height": "^2.0.3",
|
"react-height": "^2.0.3",
|
||||||
"react-helmet": "^2.3.1",
|
"react-helmet": "^2.3.1",
|
||||||
"react-intl": "=2.0.0-beta-2",
|
"react-intl": "=v2.0.0-rc-1",
|
||||||
"react-motion": "^0.4.0",
|
"react-motion": "^0.4.0",
|
||||||
"react-redux": "^4.0.0",
|
"react-redux": "^4.0.0",
|
||||||
"react-router": "^2.0.0",
|
"react-router": "^2.0.0",
|
||||||
|
@ -3,30 +3,33 @@
|
|||||||
*/
|
*/
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
|
||||||
import AuthError from './AuthError';
|
import AuthError from 'components/auth/authError/AuthError';
|
||||||
|
import { userShape } from 'components/user/User';
|
||||||
|
|
||||||
export default class BaseAuthBody extends Component {
|
export default class BaseAuthBody extends Component {
|
||||||
static propTypes = {
|
static contextTypes = {
|
||||||
clearErrors: PropTypes.func.isRequired,
|
clearErrors: PropTypes.func.isRequired,
|
||||||
resolve: PropTypes.func.isRequired,
|
resolve: PropTypes.func.isRequired,
|
||||||
reject: PropTypes.func.isRequired,
|
reject: PropTypes.func.isRequired,
|
||||||
auth: PropTypes.shape({
|
auth: PropTypes.shape({
|
||||||
error: PropTypes.string
|
error: PropTypes.string,
|
||||||
})
|
scopes: PropTypes.array
|
||||||
|
}),
|
||||||
|
user: userShape
|
||||||
};
|
};
|
||||||
|
|
||||||
renderErrors() {
|
renderErrors() {
|
||||||
return this.props.auth.error
|
return this.context.auth.error
|
||||||
? <AuthError error={this.props.auth.error} onClose={this.onClearErrors} />
|
? <AuthError error={this.context.auth.error} onClose={this.onClearErrors} />
|
||||||
: ''
|
: ''
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
onFormSubmit() {
|
onFormSubmit() {
|
||||||
this.props.resolve(this.serialize());
|
this.context.resolve(this.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
onClearErrors = this.props.clearErrors;
|
onClearErrors = this.context.clearErrors;
|
||||||
|
|
||||||
form = {};
|
form = {};
|
||||||
|
|
||||||
@ -39,6 +42,35 @@ export default class BaseAuthBody extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes some issues with scroll, when input beeing focused
|
||||||
|
*
|
||||||
|
* When an element is focused, by default browsers will scroll its parents to display
|
||||||
|
* focused item to user. This behavior may cause unexpected visual effects, when
|
||||||
|
* you animating apearing of an input (e.g. transform) and auto focusing it. In
|
||||||
|
* that case the browser will scroll the parent container so that input will be
|
||||||
|
* visible.
|
||||||
|
* This method will fix that issue by finding parent with overflow: hidden and
|
||||||
|
* reseting its scrollLeft value to 0.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* <input autoFocus onFocus={this.fixAutoFocus} />
|
||||||
|
*
|
||||||
|
* @param {Object} event
|
||||||
|
*/
|
||||||
|
fixAutoFocus = (event) => {
|
||||||
|
let el = event.target;
|
||||||
|
|
||||||
|
while (el.parentNode) {
|
||||||
|
el = el.parentNode;
|
||||||
|
|
||||||
|
if (getComputedStyle(el).overflow === 'hidden') {
|
||||||
|
el.scrollLeft = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return Object.keys(this.form).reduce((acc, key) => {
|
return Object.keys(this.form).reduce((acc, key) => {
|
||||||
acc[key] = this.form[key].getValue();
|
acc[key] = this.form[key].getValue();
|
||||||
|
@ -10,6 +10,7 @@ import {helpLinks as helpLinksStyles} from 'components/auth/helpLinks.scss';
|
|||||||
import panelStyles from 'components/ui/panel.scss';
|
import panelStyles from 'components/ui/panel.scss';
|
||||||
import icons from 'components/ui/icons.scss';
|
import icons from 'components/ui/icons.scss';
|
||||||
import authFlow from 'services/authFlow';
|
import authFlow from 'services/authFlow';
|
||||||
|
import { userShape } from 'components/user/User';
|
||||||
|
|
||||||
import * as actions from './actions';
|
import * as actions from './actions';
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ class PanelTransition extends Component {
|
|||||||
static displayName = 'PanelTransition';
|
static displayName = 'PanelTransition';
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
// context props
|
||||||
auth: PropTypes.shape({
|
auth: PropTypes.shape({
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
login: PropTypes.shape({
|
login: PropTypes.shape({
|
||||||
@ -28,8 +30,13 @@ class PanelTransition extends Component {
|
|||||||
password: PropTypes.string
|
password: PropTypes.string
|
||||||
})
|
})
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
|
user: userShape.isRequired,
|
||||||
setError: React.PropTypes.func.isRequired,
|
setError: React.PropTypes.func.isRequired,
|
||||||
clearErrors: React.PropTypes.func.isRequired,
|
clearErrors: React.PropTypes.func.isRequired,
|
||||||
|
resolve: React.PropTypes.func.isRequired,
|
||||||
|
reject: React.PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
// local props
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
Title: PropTypes.element.isRequired,
|
Title: PropTypes.element.isRequired,
|
||||||
Body: PropTypes.element.isRequired,
|
Body: PropTypes.element.isRequired,
|
||||||
@ -37,6 +44,30 @@ class PanelTransition extends Component {
|
|||||||
Links: PropTypes.element.isRequired
|
Links: PropTypes.element.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static childContextTypes = {
|
||||||
|
auth: PropTypes.shape({
|
||||||
|
error: PropTypes.string,
|
||||||
|
login: PropTypes.shape({
|
||||||
|
login: PropTypes.string,
|
||||||
|
password: PropTypes.string
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
user: userShape,
|
||||||
|
clearErrors: React.PropTypes.func,
|
||||||
|
resolve: PropTypes.func,
|
||||||
|
reject: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
getChildContext() {
|
||||||
|
return {
|
||||||
|
auth: this.props.auth,
|
||||||
|
user: this.props.user,
|
||||||
|
clearErrors: this.props.clearErrors,
|
||||||
|
resolve: this.props.resolve,
|
||||||
|
reject: this.props.reject
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
height: {},
|
height: {},
|
||||||
contextHeight: 0
|
contextHeight: 0
|
||||||
@ -91,7 +122,7 @@ class PanelTransition extends Component {
|
|||||||
|
|
||||||
const contentHeight = {
|
const contentHeight = {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
height: forceHeight ? common.switchContextHeightSpring : 'auto'
|
height: forceHeight ? common.style.switchContextHeightSpring : 'auto'
|
||||||
};
|
};
|
||||||
|
|
||||||
const bodyHeight = {
|
const bodyHeight = {
|
||||||
@ -141,6 +172,7 @@ class PanelTransition extends Component {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} config
|
* @param {Object} config
|
||||||
|
* @param {string} config.key
|
||||||
* @param {Object} [options]
|
* @param {Object} [options]
|
||||||
* @param {Object} [options.isLeave=false] - true, if this is a leave transition
|
* @param {Object} [options.isLeave=false] - true, if this is a leave transition
|
||||||
*
|
*
|
||||||
@ -235,7 +267,7 @@ class PanelTransition extends Component {
|
|||||||
<div key={`header${key}`} style={style}>
|
<div key={`header${key}`} style={style}>
|
||||||
{hasBackButton ? backButton : null}
|
{hasBackButton ? backButton : null}
|
||||||
<div style={scrollStyle}>
|
<div style={scrollStyle}>
|
||||||
{React.cloneElement(Title, this.props)}
|
{Title}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -263,7 +295,6 @@ class PanelTransition extends Component {
|
|||||||
return (
|
return (
|
||||||
<ReactHeight key={`body${key}`} style={style} onHeightReady={this.onUpdateHeight}>
|
<ReactHeight key={`body${key}`} style={style} onHeightReady={this.onUpdateHeight}>
|
||||||
{React.cloneElement(Body, {
|
{React.cloneElement(Body, {
|
||||||
...this.props,
|
|
||||||
ref: (body) => {
|
ref: (body) => {
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
@ -279,7 +310,7 @@ class PanelTransition extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`footer${key}`} style={style}>
|
<div key={`footer${key}`} style={style}>
|
||||||
{React.cloneElement(Footer, this.props)}
|
{Footer}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -291,15 +322,15 @@ class PanelTransition extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`links${key}`} style={style}>
|
<div key={`links${key}`} style={style}>
|
||||||
{React.cloneElement(Links, this.props)}
|
{Links}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
* @param {Object} props
|
* @param {Object} style
|
||||||
* @param {number} props.opacitySpring
|
* @param {number} style.opacitySpring
|
||||||
*
|
*
|
||||||
* @return {Object}
|
* @return {Object}
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -6,20 +6,12 @@ import Helmet from 'react-helmet';
|
|||||||
import buttons from 'components/ui/buttons.scss';
|
import buttons from 'components/ui/buttons.scss';
|
||||||
import { Input } from 'components/ui/Form';
|
import { Input } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import styles from './activation.scss';
|
import styles from './activation.scss';
|
||||||
import messages from './Activation.messages';
|
import messages from './Activation.messages';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'ActivationBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
login: PropTypes.shape({
|
|
||||||
login: PropTypes.stirng
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -31,7 +23,7 @@ class Body extends BaseAuthBody {
|
|||||||
|
|
||||||
<div className={styles.descriptionText}>
|
<div className={styles.descriptionText}>
|
||||||
<Message {...messages.activationMailWasSent} values={{
|
<Message {...messages.activationMailWasSent} values={{
|
||||||
email: (<b>{this.props.user.email}</b>)
|
email: (<b>{this.context.user.email}</b>)
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,6 +32,7 @@ class Body extends BaseAuthBody {
|
|||||||
color="blue"
|
color="blue"
|
||||||
className={styles.activationCodeInput}
|
className={styles.activationCodeInput}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={messages.enterTheCode}
|
placeholder={messages.enterTheCode}
|
||||||
/>
|
/>
|
@ -11,8 +11,8 @@ export default class AppInfo extends Component {
|
|||||||
static displayName = 'AppInfo';
|
static displayName = 'AppInfo';
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string,
|
||||||
description: PropTypes.string.isRequired,
|
description: PropTypes.string,
|
||||||
onGoToAuth: PropTypes.func.isRequired
|
onGoToAuth: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -6,22 +6,13 @@ import Helmet from 'react-helmet';
|
|||||||
import buttons from 'components/ui/buttons.scss';
|
import buttons from 'components/ui/buttons.scss';
|
||||||
import { Input } from 'components/ui/Form';
|
import { Input } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import messages from './ForgotPassword.messages';
|
import messages from './ForgotPassword.messages';
|
||||||
|
|
||||||
import styles from './forgotPassword.scss';
|
import styles from './forgotPassword.scss';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'ForgotPasswordBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
//login: PropTypes.func.isRequired,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
login: PropTypes.shape({
|
|
||||||
email: PropTypes.stirng
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
// Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить?
|
// Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить?
|
||||||
render() {
|
render() {
|
||||||
@ -37,6 +28,7 @@ class Body extends BaseAuthBody {
|
|||||||
icon="envelope"
|
icon="envelope"
|
||||||
color="lightViolet"
|
color="lightViolet"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={messages.accountEmail}
|
placeholder={messages.accountEmail}
|
||||||
/>
|
/>
|
||||||
@ -49,7 +41,6 @@ class Body extends BaseAuthBody {
|
|||||||
|
|
||||||
onFormSubmit() {
|
onFormSubmit() {
|
||||||
// TODO: обработчик отправки письма с инструкцией по смене аккаунта
|
// TODO: обработчик отправки письма с инструкцией по смене аккаунта
|
||||||
//this.props.login(this.serialize());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -7,20 +7,12 @@ import { Link } from 'react-router';
|
|||||||
import buttons from 'components/ui/buttons.scss';
|
import buttons from 'components/ui/buttons.scss';
|
||||||
import { Input } from 'components/ui/Form';
|
import { Input } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
|
import passwordMessages from 'components/auth/password/Password.messages';
|
||||||
import messages from './Login.messages';
|
import messages from './Login.messages';
|
||||||
import passwordMessages from './Password.messages';
|
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'LoginBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
login: PropTypes.shape({
|
|
||||||
login: PropTypes.stirng
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -30,6 +22,7 @@ class Body extends BaseAuthBody {
|
|||||||
<Input {...this.bindField('login')}
|
<Input {...this.bindField('login')}
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={messages.emailOrUsername}
|
placeholder={messages.emailOrUsername}
|
||||||
/>
|
/>
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -8,24 +8,15 @@ import buttons from 'components/ui/buttons.scss';
|
|||||||
import icons from 'components/ui/icons.scss';
|
import icons from 'components/ui/icons.scss';
|
||||||
import { Input, Checkbox } from 'components/ui/Form';
|
import { Input, Checkbox } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import styles from './password.scss';
|
import styles from './password.scss';
|
||||||
import messages from './Password.messages';
|
import messages from './Password.messages';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'PasswordBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
login: PropTypes.shape({
|
|
||||||
login: PropTypes.stirng,
|
|
||||||
password: PropTypes.stirng
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {user} = this.props;
|
const {user} = this.context;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -46,6 +37,7 @@ class Body extends BaseAuthBody {
|
|||||||
icon="key"
|
icon="key"
|
||||||
type="password"
|
type="password"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={messages.accountPassword}
|
placeholder={messages.accountPassword}
|
||||||
/>
|
/>
|
@ -2,21 +2,18 @@ import React, { PropTypes } from 'react';
|
|||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
import buttons from 'components/ui/buttons.scss';
|
import buttons from 'components/ui/buttons.scss';
|
||||||
import { Input } from 'components/ui/Form';
|
import { Input } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import passwordChangedMessages from './PasswordChange.messages';
|
import passwordChangedMessages from './PasswordChange.messages';
|
||||||
|
|
||||||
import icons from 'components/ui/icons.scss';
|
import icons from 'components/ui/icons.scss';
|
||||||
import styles from './passwordChange.scss';
|
import styles from './passwordChange.scss';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'PasswordChangeBody';
|
||||||
...BaseAuthBody.propTypes
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -35,6 +32,7 @@ class Body extends BaseAuthBody {
|
|||||||
icon="key"
|
icon="key"
|
||||||
color="darkBlue"
|
color="darkBlue"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={passwordChangedMessages.newPassword}
|
placeholder={passwordChangedMessages.newPassword}
|
||||||
/>
|
/>
|
||||||
@ -51,7 +49,7 @@ class Body extends BaseAuthBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PasswordChange() {
|
export default function PasswordChange() {
|
||||||
return {
|
const componentsMap = {
|
||||||
Title: () => ( // TODO: separate component for PageTitle
|
Title: () => ( // TODO: separate component for PageTitle
|
||||||
<Message {...passwordChangedMessages.changePasswordTitle}>
|
<Message {...passwordChangedMessages.changePasswordTitle}>
|
||||||
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
|
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
|
||||||
@ -63,14 +61,20 @@ export default function PasswordChange() {
|
|||||||
<Message {...passwordChangedMessages.change} />
|
<Message {...passwordChangedMessages.change} />
|
||||||
</button>
|
</button>
|
||||||
),
|
),
|
||||||
Links: (props) => (
|
Links: (props, context) => (
|
||||||
<a href="#" onClick={(event) => {
|
<a href="#" onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
props.reject();
|
context.reject();
|
||||||
}}>
|
}}>
|
||||||
<Message {...passwordChangedMessages.skipThisStep} />
|
<Message {...passwordChangedMessages.skipThisStep} />
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentsMap.Links.contextTypes = {
|
||||||
|
reject: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
return componentsMap;
|
||||||
}
|
}
|
@ -7,22 +7,16 @@ import buttons from 'components/ui/buttons.scss';
|
|||||||
import icons from 'components/ui/icons.scss';
|
import icons from 'components/ui/icons.scss';
|
||||||
import { PanelBodyHeader } from 'components/ui/Panel';
|
import { PanelBodyHeader } from 'components/ui/Panel';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import styles from './permissions.scss';
|
import styles from './permissions.scss';
|
||||||
import messages from './Permissions.messages';
|
import messages from './Permissions.messages';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'PermissionsBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
scopes: PropTypes.array.isRequired
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {user} = this.props;
|
const {user} = this.context;
|
||||||
const scopes = this.props.auth.scopes;
|
const scopes = this.context.auth.scopes;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,7 +55,7 @@ class Body extends BaseAuthBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Permissions() {
|
export default function Permissions() {
|
||||||
return {
|
const componentsMap = {
|
||||||
Title: () => ( // TODO: separate component for PageTitle
|
Title: () => ( // TODO: separate component for PageTitle
|
||||||
<Message {...messages.permissionsTitle}>
|
<Message {...messages.permissionsTitle}>
|
||||||
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
|
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
|
||||||
@ -73,14 +67,20 @@ export default function Permissions() {
|
|||||||
<Message {...messages.approve} />
|
<Message {...messages.approve} />
|
||||||
</button>
|
</button>
|
||||||
),
|
),
|
||||||
Links: (props) => (
|
Links: (props, context) => (
|
||||||
<a href="#" onClick={(event) => {
|
<a href="#" onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
props.reject();
|
context.reject();
|
||||||
}}>
|
}}>
|
||||||
<Message {...messages.decline} />
|
<Message {...messages.decline} />
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentsMap.Links.contextTypes = {
|
||||||
|
reject: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
return componentsMap;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage as Message } from 'react-intl';
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
@ -6,27 +6,14 @@ import Helmet from 'react-helmet';
|
|||||||
import buttons from 'components/ui/buttons.scss';
|
import buttons from 'components/ui/buttons.scss';
|
||||||
import { Input, Checkbox } from 'components/ui/Form';
|
import { Input, Checkbox } from 'components/ui/Form';
|
||||||
|
|
||||||
import BaseAuthBody from './BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
|
import activationMessages from 'components/auth/activation/Activation.messages';
|
||||||
import messages from './Register.messages';
|
import messages from './Register.messages';
|
||||||
import activationMessages from './Activation.messages';
|
|
||||||
|
|
||||||
// TODO: password and username can be validate for length and sameness
|
// TODO: password and username can be validate for length and sameness
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static propTypes = {
|
static displayName = 'RegisterBody';
|
||||||
...BaseAuthBody.propTypes,
|
|
||||||
register: PropTypes.func.isRequired,
|
|
||||||
auth: PropTypes.shape({
|
|
||||||
error: PropTypes.string,
|
|
||||||
register: PropTypes.shape({
|
|
||||||
email: PropTypes.string,
|
|
||||||
username: PropTypes.stirng,
|
|
||||||
password: PropTypes.stirng,
|
|
||||||
rePassword: PropTypes.stirng,
|
|
||||||
rulesAgreement: PropTypes.boolean
|
|
||||||
})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -38,6 +25,7 @@ class Body extends BaseAuthBody {
|
|||||||
color="blue"
|
color="blue"
|
||||||
type="text"
|
type="text"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
onFocus={this.fixAutoFocus}
|
||||||
required
|
required
|
||||||
placeholder={messages.yourNickname}
|
placeholder={messages.yourNickname}
|
||||||
/>
|
/>
|
@ -14,7 +14,7 @@ export class Input extends Component {
|
|||||||
id: PropTypes.string
|
id: PropTypes.string
|
||||||
}),
|
}),
|
||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
color: PropTypes.oneOf(['green', 'blue', 'red'])
|
color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue'])
|
||||||
};
|
};
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
13
src/index.js
13
src/index.js
@ -22,19 +22,6 @@ import routesFactory from 'routes';
|
|||||||
|
|
||||||
import 'index.scss';
|
import 'index.scss';
|
||||||
|
|
||||||
// TODO: временная мера против Intl, который беспощадно спамит консоль
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
const originalConsoleError = console.error;
|
|
||||||
if (console.error === originalConsoleError) {
|
|
||||||
console.error = (...args) => {
|
|
||||||
if (args[0].indexOf('[React Intl] Missing message:') === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
originalConsoleError.call(console, ...args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const reducer = combineReducers({
|
const reducer = combineReducers({
|
||||||
...reducers,
|
...reducers,
|
||||||
routing: routeReducer
|
routing: routeReducer
|
||||||
|
@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import AppInfo from 'components/auth/AppInfo';
|
import AppInfo from 'components/auth/appInfo/AppInfo';
|
||||||
import PanelTransition from 'components/auth/PanelTransition';
|
import PanelTransition from 'components/auth/PanelTransition';
|
||||||
|
|
||||||
import Finish from 'components/auth/Finish';
|
import Finish from 'components/auth/Finish';
|
||||||
|
@ -2,17 +2,9 @@ import React, { Component } from 'react';
|
|||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import authFlow from 'services/authFlow';
|
|
||||||
|
|
||||||
class IndexPage extends Component {
|
class IndexPage extends Component {
|
||||||
displayName = 'IndexPage';
|
displayName = 'IndexPage';
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
if (this.props.user.isGuest) {
|
|
||||||
authFlow.login();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {user, children} = this.props;
|
const {user, children} = this.props;
|
||||||
|
|
||||||
|
@ -8,14 +8,14 @@ import AuthPage from 'pages/auth/AuthPage';
|
|||||||
import { authenticate } from 'components/user/actions';
|
import { authenticate } from 'components/user/actions';
|
||||||
|
|
||||||
import OAuthInit from 'components/auth/OAuthInit';
|
import OAuthInit from 'components/auth/OAuthInit';
|
||||||
import Register from 'components/auth/Register';
|
import Register from 'components/auth/register/Register';
|
||||||
import Login from 'components/auth/Login';
|
import Login from 'components/auth/login/Login';
|
||||||
import Permissions from 'components/auth/Permissions';
|
import Permissions from 'components/auth/permissions/Permissions';
|
||||||
import Activation from 'components/auth/Activation';
|
import Activation from 'components/auth/activation/Activation';
|
||||||
import Password from 'components/auth/Password';
|
import Password from 'components/auth/password/Password';
|
||||||
import Logout from 'components/auth/Logout';
|
import Logout from 'components/auth/Logout';
|
||||||
import PasswordChange from 'components/auth/PasswordChange';
|
import PasswordChange from 'components/auth/passwordChange/PasswordChange';
|
||||||
import ForgotPassword from 'components/auth/ForgotPassword';
|
import ForgotPassword from 'components/auth/forgotPassword/ForgotPassword';
|
||||||
import Finish from 'components/auth/Finish';
|
import Finish from 'components/auth/Finish';
|
||||||
|
|
||||||
import authFlow from 'services/authFlow';
|
import authFlow from 'services/authFlow';
|
||||||
@ -35,7 +35,7 @@ export default function routesFactory(store) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Route path="/" component={RootPage}>
|
<Route path="/" component={RootPage}>
|
||||||
<IndexRoute component={IndexPage} />
|
<IndexRoute component={IndexPage} {...onEnter} />
|
||||||
|
|
||||||
<Route path="oauth" component={OAuthInit} {...onEnter} />
|
<Route path="oauth" component={OAuthInit} {...onEnter} />
|
||||||
<Route path="logout" component={Logout} {...onEnter} />
|
<Route path="logout" component={Logout} {...onEnter} />
|
||||||
|
@ -23,7 +23,6 @@ export default class AuthFlow {
|
|||||||
const {routing} = this.getState();
|
const {routing} = this.getState();
|
||||||
|
|
||||||
if (routing.location.pathname !== route) {
|
if (routing.location.pathname !== route) {
|
||||||
this.ignoreRequest = true; // TODO: remove me
|
|
||||||
if (this.replace) {
|
if (this.replace) {
|
||||||
this.replace(route);
|
this.replace(route);
|
||||||
}
|
}
|
||||||
@ -62,10 +61,10 @@ export default class AuthFlow {
|
|||||||
throw new Error('State is required');
|
throw new Error('State is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state instanceof state.constructor) {
|
// if (this.state instanceof state.constructor) {
|
||||||
// already in this state
|
// // already in this state
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.state && this.state.leave(this);
|
this.state && this.state.leave(this);
|
||||||
this.state = state;
|
this.state = state;
|
||||||
@ -74,10 +73,6 @@ export default class AuthFlow {
|
|||||||
|
|
||||||
handleRequest(path, replace) {
|
handleRequest(path, replace) {
|
||||||
this.replace = replace;
|
this.replace = replace;
|
||||||
if (this.ignoreRequest) {
|
|
||||||
this.ignoreRequest = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case '/oauth':
|
case '/oauth':
|
||||||
@ -92,6 +87,7 @@ export default class AuthFlow {
|
|||||||
this.setState(new ForgotPasswordState());
|
this.setState(new ForgotPasswordState());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '/':
|
||||||
case '/login':
|
case '/login':
|
||||||
case '/password':
|
case '/password':
|
||||||
case '/activation':
|
case '/activation':
|
||||||
|
Loading…
Reference in New Issue
Block a user