From 60e80b3319e6add74da51671daf3eb8b15f4f68b Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 4 Mar 2016 00:27:33 +0300 Subject: [PATCH 01/15] =?UTF-8?q?=D0=97=D0=B0=D0=B2=D1=91=D1=80=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D1=87=D0=BD=D1=8B=D1=85=20=D1=80=D0=B5=D0=B8=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Finish.jsx | 106 +++++++++++++++++++++++++ src/components/auth/Finish.messages.js | 24 ++++++ src/components/auth/finish.scss | 67 ++++++++++++++++ src/pages/auth/AuthPage.jsx | 4 +- src/routes.js | 2 + 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 src/components/auth/Finish.jsx create mode 100644 src/components/auth/Finish.messages.js create mode 100644 src/components/auth/finish.scss diff --git a/src/components/auth/Finish.jsx b/src/components/auth/Finish.jsx new file mode 100644 index 0000000..61e2b5f --- /dev/null +++ b/src/components/auth/Finish.jsx @@ -0,0 +1,106 @@ +import React, { Component, PropTypes } from 'react'; + +import { FormattedMessage as Message } from 'react-intl'; +import Helmet from 'react-helmet'; +import classNames from 'classnames'; + +import buttons from 'components/ui/buttons.scss'; +import { Input } from 'components/ui/Form'; + +import BaseAuthBody from './BaseAuthBody'; +import messages from './Finish.messages'; + +import styles from './finish.scss'; + +export default class Finish extends Component { + static propTypes = { + + }; + + state = { + isSidebarHidden: false + }; + + handleCopyClick(selector) { + // http://stackoverflow.com/a/987376/5184751 + var text = document.querySelector(selector); + var range, selection; + if (document.body.createTextRange) { + range = document.body.createTextRange(); + range.moveToElementText(text); + range.select(); + } else if (window.getSelection) { + selection = window.getSelection(); + range = document.createRange(); + range.selectNodeContents(text); + selection.removeAllRanges(); + selection.addRange(range); + } + + try { + var successful = document.execCommand('copy'); + // TODO: было бы ещё неплохо сделать какую-то анимацию, вроде "Скопировано", + // ибо сейчас после клика как-то неубедительно, скопировалось оно или нет + console.log('Copying text command was ' + (successful ? 'successful' : 'unsuccessful')); + } catch (err) { + console.error('Oops, unable to copy'); + } + } + + render() { + const withCode = true; + const success = true; + const appName = 'TLauncher'; + const code = 'HW9vkZA6Y4vRN3ciSm1IIDk98PHLkPPlv3jvo1MX'; + const copySupported = document.queryCommandSupported('copy'); + + return ( +
+ {success ? ( +
+
+
+ {appName}) + }} /> +
+ {withCode ? ( +
+
+ +
+
{code}
+ {copySupported ? ( +
+ +
+ ) : ( + '' + )} +
+ ) : ( +
+ +
+ )} +
+ ) : ( +
+
+
+ {appName}) + }} /> +
+
+ +
+
+ )} +
+ ); + } +} diff --git a/src/components/auth/Finish.messages.js b/src/components/auth/Finish.messages.js new file mode 100644 index 0000000..aacf2a2 --- /dev/null +++ b/src/components/auth/Finish.messages.js @@ -0,0 +1,24 @@ +import { defineMessages } from 'react-intl'; + +export default defineMessages({ + authForAppSuccessful: { + id: 'authForAppSuccessful', + defaultMessage: 'Авторизация для {appName} успешно выполнена' + }, + authForAppFailed: { + id: 'authForAppFailed', + defaultMessage: 'Авторизация для {appName} не удалась' + }, + waitAppReaction: { + id: 'waitAppReaction', + defaultMessage: 'Пожалуйста, дождитесь реакции вашего приложения' + }, + passCodeToApp: { + id: 'passCodeToApp', + defaultMessage: 'Чтобы завершить процесс авторизации, пожалуйста, передай {appName} этот код' + }, + copy: { + id: 'copy', + defaultMessage: 'Скопировать' + } +}); diff --git a/src/components/auth/finish.scss b/src/components/auth/finish.scss new file mode 100644 index 0000000..4982284 --- /dev/null +++ b/src/components/auth/finish.scss @@ -0,0 +1,67 @@ +@import '~components/ui/colors.scss'; +@import '~components/ui/fonts.scss'; + +.finishPage { + font-family: $font-family-title; + position: relative; + padding-top: 40px; +} + +.iconBackground { + position: absolute; + top: -15px; + transform: translateX(-50%); + font-size: 200px; + color: #e0d9cf; + z-index: -1; +} + +.successBackground { + composes: checkmark from 'components/ui/icons.scss'; + @extend .iconBackground; +} + +.failBackground { + composes: close from 'components/ui/icons.scss'; + @extend .iconBackground; +} + +.title { + font-size: 22px; + margin-bottom: 10px; +} + +.greenTitle { + composes: title; + + color: $green; + + .appName { + color: darker($green); + } +} + +.redTitle { + composes: title; + + color: $red; + + .appName { + color: darker($red); + } +} + +.description { + font-size: 18px; + margin-bottom: 10px; +} + +.code { + $border: 5px solid darker($green); + + border-right: $border; + border-left: $border; + padding: 5px 0; + margin-bottom: 5px; + word-break: break-all; +} diff --git a/src/pages/auth/AuthPage.jsx b/src/pages/auth/AuthPage.jsx index d31bcc2..4000410 100644 --- a/src/pages/auth/AuthPage.jsx +++ b/src/pages/auth/AuthPage.jsx @@ -5,6 +5,8 @@ import { connect } from 'react-redux'; import AppInfo from 'components/auth/AppInfo'; import PanelTransition from 'components/auth/PanelTransition'; +import Finish from 'components/auth/Finish'; + import styles from './auth.scss'; class AuthPage extends Component { @@ -31,7 +33,7 @@ class AuthPage extends Component {
- +
); diff --git a/src/routes.js b/src/routes.js index 679c4e1..56c7e86 100644 --- a/src/routes.js +++ b/src/routes.js @@ -16,6 +16,7 @@ import Password from 'components/auth/Password'; import Logout from 'components/auth/Logout'; import PasswordChange from 'components/auth/PasswordChange'; import ForgotPassword from 'components/auth/ForgotPassword'; +import Finish from 'components/auth/Finish'; import authFlow from 'services/authFlow'; @@ -47,6 +48,7 @@ export default function routesFactory(store) { + ); From c8b112b63fd1de78e01484e3a0d8d821ff304e25 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Thu, 10 Mar 2016 11:25:21 +0200 Subject: [PATCH 02/15] react-intl 2-rc1 --- package.json | 2 +- src/index.js | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/package.json b/package.json index 5e4a4dc..219f1a5 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "react-dom": "^0.14.3", "react-height": "^2.0.3", "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-redux": "^4.0.0", "react-router": "^2.0.0", diff --git a/src/index.js b/src/index.js index 34aae70..2ef133f 100644 --- a/src/index.js +++ b/src/index.js @@ -22,19 +22,6 @@ import routesFactory from 'routes'; 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({ ...reducers, routing: routeReducer From da5f684467b9dde04719ec9f672c9f7ce1517b4b Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Thu, 10 Mar 2016 12:00:19 +0200 Subject: [PATCH 03/15] react 15.0.0-rc.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 219f1a5..0610b7d 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "history": "^1.17.0", "intl-format-cache": "^2.0.4", "intl-messageformat": "^1.1.0", - "react": "^0.14.0", - "react-dom": "^0.14.3", + "react": "^15.0.0-rc.1", + "react-dom": "^15.0.0-rc.1", "react-height": "^2.0.3", "react-helmet": "^2.3.1", "react-intl": "=v2.0.0-rc-1", From a88e958c7c038ae304e24c85281cf65936b51eae Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sat, 12 Mar 2016 16:23:55 +0200 Subject: [PATCH 04/15] =?UTF-8?q?=D0=9F=D0=BE=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D1=80=D1=8B=D0=B3=D0=B0=D1=8E=D1=89=D1=83?= =?UTF-8?q?=D1=8E=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0=D1=86=D0=B8=D1=8E=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Activation.jsx | 1 + src/components/auth/BaseAuthBody.jsx | 29 +++++++++++++++++++++++++ src/components/auth/ForgotPassword.jsx | 1 + src/components/auth/Login.jsx | 1 + src/components/auth/PanelTransition.jsx | 7 +++--- src/components/auth/Password.jsx | 1 + src/components/auth/PasswordChange.jsx | 1 + src/components/auth/Register.jsx | 1 + 8 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/components/auth/Activation.jsx b/src/components/auth/Activation.jsx index b02bf18..d1b62b8 100644 --- a/src/components/auth/Activation.jsx +++ b/src/components/auth/Activation.jsx @@ -40,6 +40,7 @@ class Body extends BaseAuthBody { color="blue" className={styles.activationCodeInput} autoFocus + onFocus={this.fixAutoFocus} required placeholder={messages.enterTheCode} /> diff --git a/src/components/auth/BaseAuthBody.jsx b/src/components/auth/BaseAuthBody.jsx index f83412a..b745466 100644 --- a/src/components/auth/BaseAuthBody.jsx +++ b/src/components/auth/BaseAuthBody.jsx @@ -39,6 +39,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: + * + * + * @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() { return Object.keys(this.form).reduce((acc, key) => { acc[key] = this.form[key].getValue(); diff --git a/src/components/auth/ForgotPassword.jsx b/src/components/auth/ForgotPassword.jsx index 6f86f13..4f5dbc5 100644 --- a/src/components/auth/ForgotPassword.jsx +++ b/src/components/auth/ForgotPassword.jsx @@ -37,6 +37,7 @@ class Body extends BaseAuthBody { icon="envelope" color="lightViolet" autoFocus + onFocus={this.fixAutoFocus} required placeholder={messages.accountEmail} /> diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 0bcf7bc..7dace24 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -30,6 +30,7 @@ class Body extends BaseAuthBody { diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index 84aac19..d3f4400 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -91,7 +91,7 @@ class PanelTransition extends Component { const contentHeight = { overflow: 'hidden', - height: forceHeight ? common.switchContextHeightSpring : 'auto' + height: forceHeight ? common.style.switchContextHeightSpring : 'auto' }; const bodyHeight = { @@ -141,6 +141,7 @@ class PanelTransition extends Component { /** * @param {Object} config + * @param {string} config.key * @param {Object} [options] * @param {Object} [options.isLeave=false] - true, if this is a leave transition * @@ -298,8 +299,8 @@ class PanelTransition extends Component { /** * @param {string} key - * @param {Object} props - * @param {number} props.opacitySpring + * @param {Object} style + * @param {number} style.opacitySpring * * @return {Object} */ diff --git a/src/components/auth/Password.jsx b/src/components/auth/Password.jsx index 2c3913f..ad94865 100644 --- a/src/components/auth/Password.jsx +++ b/src/components/auth/Password.jsx @@ -46,6 +46,7 @@ class Body extends BaseAuthBody { icon="key" type="password" autoFocus + onFocus={this.fixAutoFocus} required placeholder={messages.accountPassword} /> diff --git a/src/components/auth/PasswordChange.jsx b/src/components/auth/PasswordChange.jsx index a326232..fb09742 100644 --- a/src/components/auth/PasswordChange.jsx +++ b/src/components/auth/PasswordChange.jsx @@ -35,6 +35,7 @@ class Body extends BaseAuthBody { icon="key" color="darkBlue" autoFocus + onFocus={this.fixAutoFocus} required placeholder={passwordChangedMessages.newPassword} /> diff --git a/src/components/auth/Register.jsx b/src/components/auth/Register.jsx index 7afb324..7284064 100644 --- a/src/components/auth/Register.jsx +++ b/src/components/auth/Register.jsx @@ -38,6 +38,7 @@ class Body extends BaseAuthBody { color="blue" type="text" autoFocus + onFocus={this.fixAutoFocus} required placeholder={messages.yourNickname} /> From 518901fb5709daa8624c614d79c9e3c5bf3109f6 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sun, 13 Mar 2016 10:36:31 +0200 Subject: [PATCH 05/15] =?UTF-8?q?=D0=98=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20=D0=B2=D0=BC=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=BE=20props=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=D1=85=20=D0=B0=D1=83=D1=82=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Activation.jsx | 14 ++------- src/components/auth/AppInfo.jsx | 4 +-- src/components/auth/BaseAuthBody.jsx | 17 ++++++----- src/components/auth/ForgotPassword.jsx | 14 ++------- src/components/auth/Login.jsx | 12 ++------ src/components/auth/PanelTransition.jsx | 38 ++++++++++++++++++++++--- src/components/auth/Password.jsx | 15 ++-------- src/components/auth/PasswordChange.jsx | 17 ++++++----- src/components/auth/Permissions.jsx | 24 ++++++++-------- src/components/auth/Register.jsx | 17 ++--------- src/components/ui/Form.jsx | 2 +- 11 files changed, 81 insertions(+), 93 deletions(-) diff --git a/src/components/auth/Activation.jsx b/src/components/auth/Activation.jsx index d1b62b8..23da91f 100644 --- a/src/components/auth/Activation.jsx +++ b/src/components/auth/Activation.jsx @@ -1,4 +1,4 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; @@ -11,15 +11,7 @@ import styles from './activation.scss'; import messages from './Activation.messages'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes, - auth: PropTypes.shape({ - error: PropTypes.string, - login: PropTypes.shape({ - login: PropTypes.stirng - }) - }) - }; + static displayName = 'ActivationBody'; render() { return ( @@ -31,7 +23,7 @@ class Body extends BaseAuthBody {
{this.props.user.email}) + email: ({this.context.user.email}) }} />
diff --git a/src/components/auth/AppInfo.jsx b/src/components/auth/AppInfo.jsx index 9a91306..1f0c9b6 100644 --- a/src/components/auth/AppInfo.jsx +++ b/src/components/auth/AppInfo.jsx @@ -11,8 +11,8 @@ export default class AppInfo extends Component { static displayName = 'AppInfo'; static propTypes = { - name: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, + name: PropTypes.string, + description: PropTypes.string, onGoToAuth: PropTypes.func.isRequired }; diff --git a/src/components/auth/BaseAuthBody.jsx b/src/components/auth/BaseAuthBody.jsx index b745466..13dc089 100644 --- a/src/components/auth/BaseAuthBody.jsx +++ b/src/components/auth/BaseAuthBody.jsx @@ -4,29 +4,32 @@ import React, { Component, PropTypes } from 'react'; import AuthError from './AuthError'; +import { userShape } from 'components/user/User'; export default class BaseAuthBody extends Component { - static propTypes = { + static contextTypes = { clearErrors: PropTypes.func.isRequired, resolve: PropTypes.func.isRequired, reject: PropTypes.func.isRequired, auth: PropTypes.shape({ - error: PropTypes.string - }) + error: PropTypes.string, + scopes: PropTypes.array + }), + user: userShape }; renderErrors() { - return this.props.auth.error - ? + return this.context.auth.error + ? : '' ; } onFormSubmit() { - this.props.resolve(this.serialize()); + this.context.resolve(this.serialize()); } - onClearErrors = this.props.clearErrors; + onClearErrors = this.context.clearErrors; form = {}; diff --git a/src/components/auth/ForgotPassword.jsx b/src/components/auth/ForgotPassword.jsx index 4f5dbc5..dbb78c1 100644 --- a/src/components/auth/ForgotPassword.jsx +++ b/src/components/auth/ForgotPassword.jsx @@ -1,4 +1,4 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; @@ -12,16 +12,7 @@ import messages from './ForgotPassword.messages'; import styles from './forgotPassword.scss'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes, - //login: PropTypes.func.isRequired, - auth: PropTypes.shape({ - error: PropTypes.string, - login: PropTypes.shape({ - email: PropTypes.stirng - }) - }) - }; + static displayName = 'ForgotPasswordBody'; // Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить? render() { @@ -50,7 +41,6 @@ class Body extends BaseAuthBody { onFormSubmit() { // TODO: обработчик отправки письма с инструкцией по смене аккаунта - //this.props.login(this.serialize()); } } diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 7dace24..d35da39 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -1,4 +1,4 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; @@ -12,15 +12,7 @@ import messages from './Login.messages'; import passwordMessages from './Password.messages'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes, - auth: PropTypes.shape({ - error: PropTypes.string, - login: PropTypes.shape({ - login: PropTypes.stirng - }) - }) - }; + static displayName = 'LoginBody'; render() { return ( diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index d3f4400..54a3b67 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -10,6 +10,7 @@ import {helpLinks as helpLinksStyles} from 'components/auth/helpLinks.scss'; import panelStyles from 'components/ui/panel.scss'; import icons from 'components/ui/icons.scss'; import authFlow from 'services/authFlow'; +import { userShape } from 'components/user/User'; import * as actions from './actions'; @@ -21,6 +22,7 @@ class PanelTransition extends Component { static displayName = 'PanelTransition'; static propTypes = { + // context props auth: PropTypes.shape({ error: PropTypes.string, login: PropTypes.shape({ @@ -28,8 +30,13 @@ class PanelTransition extends Component { password: PropTypes.string }) }).isRequired, + user: userShape.isRequired, setError: 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, Title: PropTypes.element.isRequired, Body: PropTypes.element.isRequired, @@ -37,6 +44,30 @@ class PanelTransition extends Component { 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 = { height: {}, contextHeight: 0 @@ -236,7 +267,7 @@ class PanelTransition extends Component {
{hasBackButton ? backButton : null}
- {React.cloneElement(Title, this.props)} + {Title}
); @@ -264,7 +295,6 @@ class PanelTransition extends Component { return ( {React.cloneElement(Body, { - ...this.props, ref: (body) => { this.body = body; } @@ -280,7 +310,7 @@ class PanelTransition extends Component { return (
- {React.cloneElement(Footer, this.props)} + {Footer}
); } @@ -292,7 +322,7 @@ class PanelTransition extends Component { return (
- {React.cloneElement(Links, this.props)} + {Links}
); } diff --git a/src/components/auth/Password.jsx b/src/components/auth/Password.jsx index ad94865..ddad4ae 100644 --- a/src/components/auth/Password.jsx +++ b/src/components/auth/Password.jsx @@ -1,4 +1,4 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; @@ -13,19 +13,10 @@ import styles from './password.scss'; import messages from './Password.messages'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes, - auth: PropTypes.shape({ - error: PropTypes.string, - login: PropTypes.shape({ - login: PropTypes.stirng, - password: PropTypes.stirng - }) - }) - }; + static displayName = 'PasswordBody'; render() { - const {user} = this.props; + const {user} = this.context; return (
diff --git a/src/components/auth/PasswordChange.jsx b/src/components/auth/PasswordChange.jsx index fb09742..bf22477 100644 --- a/src/components/auth/PasswordChange.jsx +++ b/src/components/auth/PasswordChange.jsx @@ -2,7 +2,6 @@ import React, { PropTypes } from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; -import { Link } from 'react-router'; import buttons from 'components/ui/buttons.scss'; import { Input } from 'components/ui/Form'; @@ -14,9 +13,7 @@ import icons from 'components/ui/icons.scss'; import styles from './passwordChange.scss'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes - }; + static displayName = 'PasswordChangeBody'; render() { return ( @@ -52,7 +49,7 @@ class Body extends BaseAuthBody { } export default function PasswordChange() { - return { + const componentsMap = { Title: () => ( // TODO: separate component for PageTitle {(msg) => {msg}} @@ -64,14 +61,20 @@ export default function PasswordChange() { ), - Links: (props) => ( + Links: (props, context) => ( { event.preventDefault(); - props.reject(); + context.reject(); }}> ) }; + + componentsMap.Links.contextTypes = { + reject: PropTypes.func.isRequired + }; + + return componentsMap; } diff --git a/src/components/auth/Permissions.jsx b/src/components/auth/Permissions.jsx index effe588..2ab2f8d 100644 --- a/src/components/auth/Permissions.jsx +++ b/src/components/auth/Permissions.jsx @@ -12,17 +12,11 @@ import styles from './permissions.scss'; import messages from './Permissions.messages'; class Body extends BaseAuthBody { - static propTypes = { - ...BaseAuthBody.propTypes, - auth: PropTypes.shape({ - error: PropTypes.string, - scopes: PropTypes.array.isRequired - }) - }; + static displayName = 'PermissionsBody'; render() { - const {user} = this.props; - const scopes = this.props.auth.scopes; + const {user} = this.context; + const scopes = this.context.auth.scopes; return (
@@ -61,7 +55,7 @@ class Body extends BaseAuthBody { } export default function Permissions() { - return { + const componentsMap = { Title: () => ( // TODO: separate component for PageTitle {(msg) => {msg}} @@ -73,14 +67,20 @@ export default function Permissions() { ), - Links: (props) => ( + Links: (props, context) => ( { event.preventDefault(); - props.reject(); + context.reject(); }}> ) }; + + componentsMap.Links.contextTypes = { + reject: PropTypes.func.isRequired + }; + + return componentsMap; } diff --git a/src/components/auth/Register.jsx b/src/components/auth/Register.jsx index 7284064..48643e3 100644 --- a/src/components/auth/Register.jsx +++ b/src/components/auth/Register.jsx @@ -1,4 +1,4 @@ -import React, { PropTypes } from 'react'; +import React from 'react'; import { FormattedMessage as Message } from 'react-intl'; import Helmet from 'react-helmet'; @@ -13,20 +13,7 @@ import activationMessages from './Activation.messages'; // TODO: password and username can be validate for length and sameness class Body extends BaseAuthBody { - static propTypes = { - ...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 - }) - }) - }; + static displayName = 'RegisterBody'; render() { return ( diff --git a/src/components/ui/Form.jsx b/src/components/ui/Form.jsx index 7dd2a25..bb59b15 100644 --- a/src/components/ui/Form.jsx +++ b/src/components/ui/Form.jsx @@ -14,7 +14,7 @@ export class Input extends Component { id: PropTypes.string }), icon: PropTypes.string, - color: PropTypes.oneOf(['green', 'blue', 'red']) + color: PropTypes.oneOf(['green', 'blue', 'red', 'lightViolet', 'darkBlue']) }; static contextTypes = { From 41015ca336f9cf4741ebeeeb7faac4dcc5b384b3 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sun, 13 Mar 2016 10:50:09 +0200 Subject: [PATCH 06/15] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B4=D0=B8=D1=80=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=20auth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/BaseAuthBody.jsx | 2 +- .../auth/{ => activation}/Activation.jsx | 2 +- .../auth/{ => activation}/Activation.messages.js | 0 .../auth/{ => activation}/activation.scss | 0 src/components/auth/{ => appInfo}/AppInfo.jsx | 0 .../auth/{ => appInfo}/AppInfo.messages.js | 0 src/components/auth/{ => appInfo}/appInfo.scss | 0 src/components/auth/{ => authError}/AuthError.jsx | 0 .../auth/{ => authError}/AuthError.messages.js | 0 .../auth/{ => forgotPassword}/ForgotPassword.jsx | 2 +- .../ForgotPassword.messages.js | 0 .../auth/{ => forgotPassword}/forgotPassword.scss | 0 src/components/auth/{ => login}/Login.jsx | 4 ++-- src/components/auth/{ => login}/Login.messages.js | 0 src/components/auth/{ => password}/Password.jsx | 2 +- .../auth/{ => password}/Password.messages.js | 0 src/components/auth/{ => password}/password.scss | 0 .../auth/{ => passwordChange}/PasswordChange.jsx | 2 +- .../PasswordChange.messages.js | 0 .../auth/{ => passwordChange}/passwordChange.scss | 0 .../auth/{ => permissions}/Permissions.jsx | 2 +- .../auth/{ => permissions}/Permissions.messages.js | 0 .../auth/{ => permissions}/permissions.scss | 0 src/components/auth/{ => register}/Register.jsx | 4 ++-- .../auth/{ => register}/Register.messages.js | 0 src/pages/auth/AuthPage.jsx | 2 +- src/routes.js | 14 +++++++------- 27 files changed, 18 insertions(+), 18 deletions(-) rename src/components/auth/{ => activation}/Activation.jsx (97%) rename src/components/auth/{ => activation}/Activation.messages.js (100%) rename src/components/auth/{ => activation}/activation.scss (100%) rename src/components/auth/{ => appInfo}/AppInfo.jsx (100%) rename src/components/auth/{ => appInfo}/AppInfo.messages.js (100%) rename src/components/auth/{ => appInfo}/appInfo.scss (100%) rename src/components/auth/{ => authError}/AuthError.jsx (100%) rename src/components/auth/{ => authError}/AuthError.messages.js (100%) rename src/components/auth/{ => forgotPassword}/ForgotPassword.jsx (97%) rename src/components/auth/{ => forgotPassword}/ForgotPassword.messages.js (100%) rename src/components/auth/{ => forgotPassword}/forgotPassword.scss (100%) rename src/components/auth/{ => login}/Login.jsx (91%) rename src/components/auth/{ => login}/Login.messages.js (100%) rename src/components/auth/{ => password}/Password.jsx (97%) rename src/components/auth/{ => password}/Password.messages.js (100%) rename src/components/auth/{ => password}/password.scss (100%) rename src/components/auth/{ => passwordChange}/PasswordChange.jsx (97%) rename src/components/auth/{ => passwordChange}/PasswordChange.messages.js (100%) rename src/components/auth/{ => passwordChange}/passwordChange.scss (100%) rename src/components/auth/{ => permissions}/Permissions.jsx (98%) rename src/components/auth/{ => permissions}/Permissions.messages.js (100%) rename src/components/auth/{ => permissions}/permissions.scss (100%) rename src/components/auth/{ => register}/Register.jsx (95%) rename src/components/auth/{ => register}/Register.messages.js (100%) diff --git a/src/components/auth/BaseAuthBody.jsx b/src/components/auth/BaseAuthBody.jsx index 13dc089..e0253f9 100644 --- a/src/components/auth/BaseAuthBody.jsx +++ b/src/components/auth/BaseAuthBody.jsx @@ -3,7 +3,7 @@ */ 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 { diff --git a/src/components/auth/Activation.jsx b/src/components/auth/activation/Activation.jsx similarity index 97% rename from src/components/auth/Activation.jsx rename to src/components/auth/activation/Activation.jsx index 23da91f..1c20d53 100644 --- a/src/components/auth/Activation.jsx +++ b/src/components/auth/activation/Activation.jsx @@ -6,7 +6,7 @@ import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; import { Input } from 'components/ui/Form'; -import BaseAuthBody from './BaseAuthBody'; +import BaseAuthBody from 'components/auth/BaseAuthBody'; import styles from './activation.scss'; import messages from './Activation.messages'; diff --git a/src/components/auth/Activation.messages.js b/src/components/auth/activation/Activation.messages.js similarity index 100% rename from src/components/auth/Activation.messages.js rename to src/components/auth/activation/Activation.messages.js diff --git a/src/components/auth/activation.scss b/src/components/auth/activation/activation.scss similarity index 100% rename from src/components/auth/activation.scss rename to src/components/auth/activation/activation.scss diff --git a/src/components/auth/AppInfo.jsx b/src/components/auth/appInfo/AppInfo.jsx similarity index 100% rename from src/components/auth/AppInfo.jsx rename to src/components/auth/appInfo/AppInfo.jsx diff --git a/src/components/auth/AppInfo.messages.js b/src/components/auth/appInfo/AppInfo.messages.js similarity index 100% rename from src/components/auth/AppInfo.messages.js rename to src/components/auth/appInfo/AppInfo.messages.js diff --git a/src/components/auth/appInfo.scss b/src/components/auth/appInfo/appInfo.scss similarity index 100% rename from src/components/auth/appInfo.scss rename to src/components/auth/appInfo/appInfo.scss diff --git a/src/components/auth/AuthError.jsx b/src/components/auth/authError/AuthError.jsx similarity index 100% rename from src/components/auth/AuthError.jsx rename to src/components/auth/authError/AuthError.jsx diff --git a/src/components/auth/AuthError.messages.js b/src/components/auth/authError/AuthError.messages.js similarity index 100% rename from src/components/auth/AuthError.messages.js rename to src/components/auth/authError/AuthError.messages.js diff --git a/src/components/auth/ForgotPassword.jsx b/src/components/auth/forgotPassword/ForgotPassword.jsx similarity index 97% rename from src/components/auth/ForgotPassword.jsx rename to src/components/auth/forgotPassword/ForgotPassword.jsx index dbb78c1..b6f33ba 100644 --- a/src/components/auth/ForgotPassword.jsx +++ b/src/components/auth/forgotPassword/ForgotPassword.jsx @@ -6,7 +6,7 @@ import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; import { Input } from 'components/ui/Form'; -import BaseAuthBody from './BaseAuthBody'; +import BaseAuthBody from 'components/auth/BaseAuthBody'; import messages from './ForgotPassword.messages'; import styles from './forgotPassword.scss'; diff --git a/src/components/auth/ForgotPassword.messages.js b/src/components/auth/forgotPassword/ForgotPassword.messages.js similarity index 100% rename from src/components/auth/ForgotPassword.messages.js rename to src/components/auth/forgotPassword/ForgotPassword.messages.js diff --git a/src/components/auth/forgotPassword.scss b/src/components/auth/forgotPassword/forgotPassword.scss similarity index 100% rename from src/components/auth/forgotPassword.scss rename to src/components/auth/forgotPassword/forgotPassword.scss diff --git a/src/components/auth/Login.jsx b/src/components/auth/login/Login.jsx similarity index 91% rename from src/components/auth/Login.jsx rename to src/components/auth/login/Login.jsx index d35da39..db0e611 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/login/Login.jsx @@ -7,9 +7,9 @@ import { Link } from 'react-router'; import buttons from 'components/ui/buttons.scss'; 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 passwordMessages from './Password.messages'; class Body extends BaseAuthBody { static displayName = 'LoginBody'; diff --git a/src/components/auth/Login.messages.js b/src/components/auth/login/Login.messages.js similarity index 100% rename from src/components/auth/Login.messages.js rename to src/components/auth/login/Login.messages.js diff --git a/src/components/auth/Password.jsx b/src/components/auth/password/Password.jsx similarity index 97% rename from src/components/auth/Password.jsx rename to src/components/auth/password/Password.jsx index ddad4ae..0297a76 100644 --- a/src/components/auth/Password.jsx +++ b/src/components/auth/password/Password.jsx @@ -8,7 +8,7 @@ import buttons from 'components/ui/buttons.scss'; import icons from 'components/ui/icons.scss'; import { Input, Checkbox } from 'components/ui/Form'; -import BaseAuthBody from './BaseAuthBody'; +import BaseAuthBody from 'components/auth/BaseAuthBody'; import styles from './password.scss'; import messages from './Password.messages'; diff --git a/src/components/auth/Password.messages.js b/src/components/auth/password/Password.messages.js similarity index 100% rename from src/components/auth/Password.messages.js rename to src/components/auth/password/Password.messages.js diff --git a/src/components/auth/password.scss b/src/components/auth/password/password.scss similarity index 100% rename from src/components/auth/password.scss rename to src/components/auth/password/password.scss diff --git a/src/components/auth/PasswordChange.jsx b/src/components/auth/passwordChange/PasswordChange.jsx similarity index 97% rename from src/components/auth/PasswordChange.jsx rename to src/components/auth/passwordChange/PasswordChange.jsx index bf22477..ec043f1 100644 --- a/src/components/auth/PasswordChange.jsx +++ b/src/components/auth/passwordChange/PasswordChange.jsx @@ -6,7 +6,7 @@ import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; import { Input } from 'components/ui/Form'; -import BaseAuthBody from './BaseAuthBody'; +import BaseAuthBody from 'components/auth/BaseAuthBody'; import passwordChangedMessages from './PasswordChange.messages'; import icons from 'components/ui/icons.scss'; diff --git a/src/components/auth/PasswordChange.messages.js b/src/components/auth/passwordChange/PasswordChange.messages.js similarity index 100% rename from src/components/auth/PasswordChange.messages.js rename to src/components/auth/passwordChange/PasswordChange.messages.js diff --git a/src/components/auth/passwordChange.scss b/src/components/auth/passwordChange/passwordChange.scss similarity index 100% rename from src/components/auth/passwordChange.scss rename to src/components/auth/passwordChange/passwordChange.scss diff --git a/src/components/auth/Permissions.jsx b/src/components/auth/permissions/Permissions.jsx similarity index 98% rename from src/components/auth/Permissions.jsx rename to src/components/auth/permissions/Permissions.jsx index 2ab2f8d..1ef715e 100644 --- a/src/components/auth/Permissions.jsx +++ b/src/components/auth/permissions/Permissions.jsx @@ -7,7 +7,7 @@ import buttons from 'components/ui/buttons.scss'; import icons from 'components/ui/icons.scss'; import { PanelBodyHeader } from 'components/ui/Panel'; -import BaseAuthBody from './BaseAuthBody'; +import BaseAuthBody from 'components/auth/BaseAuthBody'; import styles from './permissions.scss'; import messages from './Permissions.messages'; diff --git a/src/components/auth/Permissions.messages.js b/src/components/auth/permissions/Permissions.messages.js similarity index 100% rename from src/components/auth/Permissions.messages.js rename to src/components/auth/permissions/Permissions.messages.js diff --git a/src/components/auth/permissions.scss b/src/components/auth/permissions/permissions.scss similarity index 100% rename from src/components/auth/permissions.scss rename to src/components/auth/permissions/permissions.scss diff --git a/src/components/auth/Register.jsx b/src/components/auth/register/Register.jsx similarity index 95% rename from src/components/auth/Register.jsx rename to src/components/auth/register/Register.jsx index 48643e3..e4ed0a1 100644 --- a/src/components/auth/Register.jsx +++ b/src/components/auth/register/Register.jsx @@ -6,9 +6,9 @@ import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; 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 activationMessages from './Activation.messages'; // TODO: password and username can be validate for length and sameness diff --git a/src/components/auth/Register.messages.js b/src/components/auth/register/Register.messages.js similarity index 100% rename from src/components/auth/Register.messages.js rename to src/components/auth/register/Register.messages.js diff --git a/src/pages/auth/AuthPage.jsx b/src/pages/auth/AuthPage.jsx index d31bcc2..4ee6fbd 100644 --- a/src/pages/auth/AuthPage.jsx +++ b/src/pages/auth/AuthPage.jsx @@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react'; 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 styles from './auth.scss'; diff --git a/src/routes.js b/src/routes.js index 679c4e1..69d5c90 100644 --- a/src/routes.js +++ b/src/routes.js @@ -8,14 +8,14 @@ import AuthPage from 'pages/auth/AuthPage'; import { authenticate } from 'components/user/actions'; import OAuthInit from 'components/auth/OAuthInit'; -import Register from 'components/auth/Register'; -import Login from 'components/auth/Login'; -import Permissions from 'components/auth/Permissions'; -import Activation from 'components/auth/Activation'; -import Password from 'components/auth/Password'; +import Register from 'components/auth/register/Register'; +import Login from 'components/auth/login/Login'; +import Permissions from 'components/auth/permissions/Permissions'; +import Activation from 'components/auth/activation/Activation'; +import Password from 'components/auth/password/Password'; import Logout from 'components/auth/Logout'; -import PasswordChange from 'components/auth/PasswordChange'; -import ForgotPassword from 'components/auth/ForgotPassword'; +import PasswordChange from 'components/auth/passwordChange/PasswordChange'; +import ForgotPassword from 'components/auth/forgotPassword/ForgotPassword'; import authFlow from 'services/authFlow'; From 2ad00d27ff1cd3653259bcbabd0c811c46b79cb7 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sun, 13 Mar 2016 11:02:24 +0200 Subject: [PATCH 07/15] =?UTF-8?q?=D0=9F=D0=BE=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B1=D0=B0=D0=B3,=20=D0=BA=D0=BE=D0=B3=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=B3=D0=BE=D1=81=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B3=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D0=B0=D1=81=D1=82=D1=8C=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=83=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=84=D0=B8=D0=BB=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B8=D0=BA=D0=B5=20=D0=BF=D0=BE=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=81=D0=B0=D0=B9=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/index/IndexPage.jsx | 8 -------- src/routes.js | 2 +- src/services/authFlow/AuthFlow.js | 14 +++++--------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/pages/index/IndexPage.jsx b/src/pages/index/IndexPage.jsx index 427985f..9ac770e 100644 --- a/src/pages/index/IndexPage.jsx +++ b/src/pages/index/IndexPage.jsx @@ -2,17 +2,9 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import authFlow from 'services/authFlow'; - class IndexPage extends Component { displayName = 'IndexPage'; - componentWillMount() { - if (this.props.user.isGuest) { - authFlow.login(); - } - } - render() { const {user, children} = this.props; diff --git a/src/routes.js b/src/routes.js index 69d5c90..20ddaf6 100644 --- a/src/routes.js +++ b/src/routes.js @@ -34,7 +34,7 @@ export default function routesFactory(store) { return ( - + diff --git a/src/services/authFlow/AuthFlow.js b/src/services/authFlow/AuthFlow.js index c071050..b00da93 100644 --- a/src/services/authFlow/AuthFlow.js +++ b/src/services/authFlow/AuthFlow.js @@ -23,7 +23,6 @@ export default class AuthFlow { const {routing} = this.getState(); if (routing.location.pathname !== route) { - this.ignoreRequest = true; // TODO: remove me if (this.replace) { this.replace(route); } @@ -62,10 +61,10 @@ export default class AuthFlow { throw new Error('State is required'); } - if (this.state instanceof state.constructor) { - // already in this state - return; - } + // if (this.state instanceof state.constructor) { + // // already in this state + // return; + // } this.state && this.state.leave(this); this.state = state; @@ -74,10 +73,6 @@ export default class AuthFlow { handleRequest(path, replace) { this.replace = replace; - if (this.ignoreRequest) { - this.ignoreRequest = false; - return; - } switch (path) { case '/oauth': @@ -92,6 +87,7 @@ export default class AuthFlow { this.setState(new ForgotPasswordState()); break; + case '/': case '/login': case '/password': case '/activation': From 8fcfc35d95b05d263b29ba1b577ac6b533266ed7 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Tue, 15 Mar 2016 07:40:18 +0200 Subject: [PATCH 08/15] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BB=20Finish=20=D1=81=20PanelT?= =?UTF-8?q?ransition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Finish.jsx | 80 +++++++++++++------------ src/components/auth/PanelTransition.jsx | 15 +++-- src/components/auth/finish.scss | 13 +++- src/pages/auth/AuthPage.jsx | 2 +- src/routes.js | 2 +- 5 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/components/auth/Finish.jsx b/src/components/auth/Finish.jsx index 61e2b5f..4cf2c1d 100644 --- a/src/components/auth/Finish.jsx +++ b/src/components/auth/Finish.jsx @@ -1,58 +1,55 @@ import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; import { FormattedMessage as Message } from 'react-intl'; -import Helmet from 'react-helmet'; import classNames from 'classnames'; import buttons from 'components/ui/buttons.scss'; -import { Input } from 'components/ui/Form'; -import BaseAuthBody from './BaseAuthBody'; import messages from './Finish.messages'; - import styles from './finish.scss'; -export default class Finish extends Component { - static propTypes = { +class Finish extends Component { + static displayName = 'Finish'; + static propTypes = { + appName: PropTypes.string.isRequired, + code: PropTypes.string.isRequired, + displayCode: PropTypes.bool, + success: PropTypes.bool }; state = { - isSidebarHidden: false + isCopySupported: document.queryCommandSupported && document.queryCommandSupported('copy') }; - handleCopyClick(selector) { + handleCopyClick = (event) => { + event.preventDefault(); // http://stackoverflow.com/a/987376/5184751 - var text = document.querySelector(selector); - var range, selection; - if (document.body.createTextRange) { - range = document.body.createTextRange(); - range.moveToElementText(text); - range.select(); - } else if (window.getSelection) { - selection = window.getSelection(); - range = document.createRange(); - range.selectNodeContents(text); - selection.removeAllRanges(); - selection.addRange(range); - } try { - var successful = document.execCommand('copy'); + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(this.code); + selection.removeAllRanges(); + selection.addRange(range); + + const successful = document.execCommand('copy'); + selection.removeAllRanges(); + // TODO: было бы ещё неплохо сделать какую-то анимацию, вроде "Скопировано", // ибо сейчас после клика как-то неубедительно, скопировалось оно или нет console.log('Copying text command was ' + (successful ? 'successful' : 'unsuccessful')); - } catch (err) { - console.error('Oops, unable to copy'); - } - } + } catch (err) {} + }; + + setCode = (el) => { + this.code = el; + }; render() { - const withCode = true; - const success = true; - const appName = 'TLauncher'; - const code = 'HW9vkZA6Y4vRN3ciSm1IIDk98PHLkPPlv3jvo1MX'; - const copySupported = document.queryCommandSupported('copy'); + const {appName, code, displayCode, success} = this.props; + const {isCopySupported} = this.state; return (
@@ -64,19 +61,21 @@ export default class Finish extends Component { appName: ({appName}) }} />
- {withCode ? ( + {displayCode ? (
-
{code}
- {copySupported ? ( -
+
{code}
+
+ {isCopySupported ? ( +
+ ) : ( '' )} @@ -104,3 +103,10 @@ export default class Finish extends Component { ); } } + +export default connect((state) => ({ + appName: state.auth.client ? state.auth.client.name : 'Undefined', + code: 'HW9vkZA6Y4vRN3ciSm1IIDk98PHLkPPlv3jvo1MX', + displayCode: true, + success: true +}))(Finish); diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index 54a3b67..ab15178 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -38,10 +38,11 @@ class PanelTransition extends Component { // local props path: PropTypes.string.isRequired, - Title: PropTypes.element.isRequired, - Body: PropTypes.element.isRequired, - Footer: PropTypes.element.isRequired, - Links: PropTypes.element.isRequired + Title: PropTypes.element, + Body: PropTypes.element, + Footer: PropTypes.element, + Links: PropTypes.element, + children: PropTypes.element }; static childContextTypes = { @@ -101,6 +102,12 @@ class PanelTransition extends Component { const {path, Title, Body, Footer, Links} = this.props; + if (this.props.children) { + return this.props.children; + } else if (!Title || !Body || !Footer || !Links) { + throw new Error('Title, Body, Footer and Links are required'); + } + return (
- +
); diff --git a/src/routes.js b/src/routes.js index 8e976c9..78a5347 100644 --- a/src/routes.js +++ b/src/routes.js @@ -46,9 +46,9 @@ export default function routesFactory(store) { + - ); From 779cf2d187ace3f2271f0c763caeb57586353d3a Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Tue, 15 Mar 2016 07:47:31 +0200 Subject: [PATCH 09/15] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=20finish=20=D0=B2=20=D1=81=D0=B2=D0=BE=D1=8E=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=B4=D0=B8=D1=80=D0=B5=D0=BA=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/{ => finish}/Finish.jsx | 0 src/components/auth/{ => finish}/Finish.messages.js | 0 src/components/auth/{ => finish}/finish.scss | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/components/auth/{ => finish}/Finish.jsx (100%) rename src/components/auth/{ => finish}/Finish.messages.js (100%) rename src/components/auth/{ => finish}/finish.scss (100%) diff --git a/src/components/auth/Finish.jsx b/src/components/auth/finish/Finish.jsx similarity index 100% rename from src/components/auth/Finish.jsx rename to src/components/auth/finish/Finish.jsx diff --git a/src/components/auth/Finish.messages.js b/src/components/auth/finish/Finish.messages.js similarity index 100% rename from src/components/auth/Finish.messages.js rename to src/components/auth/finish/Finish.messages.js diff --git a/src/components/auth/finish.scss b/src/components/auth/finish/finish.scss similarity index 100% rename from src/components/auth/finish.scss rename to src/components/auth/finish/finish.scss From e0d93c3058e6cb4c9ed097c3b4ab65e3463eac5a Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Tue, 15 Mar 2016 08:36:13 +0200 Subject: [PATCH 10/15] =?UTF-8?q?=D0=97=D0=B0=D0=B8=D0=BC=D0=BF=D0=BB?= =?UTF-8?q?=D0=B5=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D0=BB=20finish=20state?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/actions.js | 25 +++++++++++++ src/components/auth/finish/Finish.jsx | 10 +++--- src/components/auth/reducer.js | 10 +++++- src/pages/auth/AuthPage.jsx | 2 -- src/routes.js | 4 +-- src/services/authFlow/AuthFlow.js | 1 + src/services/authFlow/CompleteState.js | 44 ++++++++++++++++++----- src/services/authFlow/FinishState.js | 7 ++++ src/services/authFlow/PermissionsState.js | 5 +-- 9 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 src/services/authFlow/FinishState.js diff --git a/src/components/auth/actions.js b/src/components/auth/actions.js index 87f6ed1..70aa9fc 100644 --- a/src/components/auth/actions.js +++ b/src/components/auth/actions.js @@ -151,6 +151,7 @@ export function oAuthComplete(params = {}) { if (resp.statusCode === 401 && resp.error === 'access_denied') { // user declined permissions return { + success: false, redirectUri: resp.redirectUri }; } @@ -168,6 +169,18 @@ export function oAuthComplete(params = {}) { error.acceptRequired = true; throw error; } + }) + .then((resp) => { + if (resp.redirectUri === 'static_page' || resp.redirectUri === 'static_page_with_code') { + resp.displayCode = resp.redirectUri === 'static_page_with_code'; + dispatch(setOAuthCode({ + success: resp.success, + code: resp.code, + displayCode: resp.displayCode + })); + } + + return resp; }); }; } @@ -224,6 +237,18 @@ export function setOAuthRequest(oauth) { }; } +export const SET_OAUTH_RESULT = 'set_oauth_result'; +export function setOAuthCode(oauth) { + return { + type: SET_OAUTH_RESULT, + payload: { + success: oauth.success, + code: oauth.code, + displayCode: oauth.displayCode + } + }; +} + export const SET_SCOPES = 'set_scopes'; export function setScopes(scopes) { if (!(scopes instanceof Array)) { diff --git a/src/components/auth/finish/Finish.jsx b/src/components/auth/finish/Finish.jsx index 4cf2c1d..9163c48 100644 --- a/src/components/auth/finish/Finish.jsx +++ b/src/components/auth/finish/Finish.jsx @@ -104,9 +104,9 @@ class Finish extends Component { } } -export default connect((state) => ({ - appName: state.auth.client ? state.auth.client.name : 'Undefined', - code: 'HW9vkZA6Y4vRN3ciSm1IIDk98PHLkPPlv3jvo1MX', - displayCode: true, - success: true +export default connect(({auth}) => ({ + appName: auth.client.name, + code: auth.oauth.code, + displayCode: auth.oauth.displayCode, + success: auth.oauth.success }))(Finish); diff --git a/src/components/auth/reducer.js b/src/components/auth/reducer.js index 402b3a3..ba33339 100644 --- a/src/components/auth/reducer.js +++ b/src/components/auth/reducer.js @@ -1,6 +1,6 @@ import { combineReducers } from 'redux'; -import { ERROR, SET_CLIENT, SET_OAUTH, SET_SCOPES } from './actions'; +import { ERROR, SET_CLIENT, SET_OAUTH, SET_OAUTH_RESULT, SET_SCOPES } from './actions'; export default combineReducers({ error, @@ -56,6 +56,14 @@ function oauth( state: payload.state }; + case SET_OAUTH_RESULT: + return { + ...state, + success: payload.success, + code: payload.code, + displayCode: payload.displayCode + }; + default: return state; } diff --git a/src/pages/auth/AuthPage.jsx b/src/pages/auth/AuthPage.jsx index 6a9fa13..4ee6fbd 100644 --- a/src/pages/auth/AuthPage.jsx +++ b/src/pages/auth/AuthPage.jsx @@ -5,8 +5,6 @@ import { connect } from 'react-redux'; import AppInfo from 'components/auth/appInfo/AppInfo'; import PanelTransition from 'components/auth/PanelTransition'; -import Finish from 'components/auth/Finish'; - import styles from './auth.scss'; class AuthPage extends Component { diff --git a/src/routes.js b/src/routes.js index 78a5347..72f4931 100644 --- a/src/routes.js +++ b/src/routes.js @@ -16,7 +16,7 @@ import Password from 'components/auth/password/Password'; import Logout from 'components/auth/Logout'; import PasswordChange from 'components/auth/passwordChange/PasswordChange'; import ForgotPassword from 'components/auth/forgotPassword/ForgotPassword'; -import Finish from 'components/auth/Finish'; +import Finish from 'components/auth/finish/Finish'; import authFlow from 'services/authFlow'; @@ -46,7 +46,7 @@ export default function routesFactory(store) { - + diff --git a/src/services/authFlow/AuthFlow.js b/src/services/authFlow/AuthFlow.js index b00da93..2dd239c 100644 --- a/src/services/authFlow/AuthFlow.js +++ b/src/services/authFlow/AuthFlow.js @@ -93,6 +93,7 @@ export default class AuthFlow { case '/activation': case '/password-change': case '/oauth/permissions': + case '/oauth/finish': this.setState(new LoginState()); break; diff --git a/src/services/authFlow/CompleteState.js b/src/services/authFlow/CompleteState.js index 153b367..6bf47f8 100644 --- a/src/services/authFlow/CompleteState.js +++ b/src/services/authFlow/CompleteState.js @@ -3,8 +3,18 @@ import LoginState from './LoginState'; import PermissionsState from './PermissionsState'; import ActivationState from './ActivationState'; import ChangePasswordState from './ChangePasswordState'; +import FinishState from './FinishState'; export default class CompleteState extends AbstractState { + constructor(options = {}) { + super(options); + + if ('accept' in options) { + this.isPermissionsAccepted = options.accept; + this.isUserReviewedPermissions = true; + } + } + enter(context) { const {auth, user} = context.getState(); @@ -15,16 +25,32 @@ export default class CompleteState extends AbstractState { } else if (user.shouldChangePassword) { context.setState(new ChangePasswordState()); } else if (auth.oauth) { - context.run('oAuthComplete').then((resp) => { - location.href = resp.redirectUri; - }, (resp) => { - // TODO - if (resp.unauthorized) { - context.setState(new LoginState()); - } else if (resp.acceptRequired) { - context.setState(new PermissionsState()); + if (auth.oauth.code) { + context.setState(new FinishState()); + } else { + let data = {}; + if (this.isUserReviewedPermissions) { + data.accept = this.isPermissionsAccepted; } - }); + context.run('oAuthComplete', data).then((resp) => { + switch (resp.redirectUri) { + case 'static_page': + case 'static_page_with_code': + context.setState(new FinishState()); + break; + default: + location.href = resp.redirectUri; + break; + } + }, (resp) => { + // TODO + if (resp.unauthorized) { + context.setState(new LoginState()); + } else if (resp.acceptRequired) { + context.setState(new PermissionsState()); + } + }); + } } else { context.navigate('/'); } diff --git a/src/services/authFlow/FinishState.js b/src/services/authFlow/FinishState.js new file mode 100644 index 0000000..275a03e --- /dev/null +++ b/src/services/authFlow/FinishState.js @@ -0,0 +1,7 @@ +import AbstractState from './AbstractState'; + +export default class CompleteState extends AbstractState { + enter(context) { + context.navigate('/oauth/finish'); + } +} diff --git a/src/services/authFlow/PermissionsState.js b/src/services/authFlow/PermissionsState.js index 87ab524..9961b8e 100644 --- a/src/services/authFlow/PermissionsState.js +++ b/src/services/authFlow/PermissionsState.js @@ -1,4 +1,5 @@ import AbstractState from './AbstractState'; +import CompleteState from './CompleteState'; export default class PermissionsState extends AbstractState { enter(context) { @@ -14,8 +15,8 @@ export default class PermissionsState extends AbstractState { } process(context, accept) { - context.run('oAuthComplete', { + context.setState(new CompleteState({ accept - }).then((resp) => location.href = resp.redirectUri); + })); } } From bd9635fc1221b7720e32b046c3be9d81429500f2 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 16 Mar 2016 06:46:44 +0200 Subject: [PATCH 11/15] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=BA=D0=B8=D0=B4?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=20=D0=B8=20=D1=81=D1=82=D0=B5=D0=B9=D1=82=D0=B0=20=D0=B2=20tit?= =?UTF-8?q?le=20=D0=B8=20hash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/finish/Finish.jsx | 60 ++++++++++++++++----------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/components/auth/finish/Finish.jsx b/src/components/auth/finish/Finish.jsx index 9163c48..7f7b7a1 100644 --- a/src/components/auth/finish/Finish.jsx +++ b/src/components/auth/finish/Finish.jsx @@ -3,6 +3,7 @@ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import { FormattedMessage as Message } from 'react-intl'; import classNames from 'classnames'; +import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; @@ -23,36 +24,20 @@ class Finish extends Component { isCopySupported: document.queryCommandSupported && document.queryCommandSupported('copy') }; - handleCopyClick = (event) => { - event.preventDefault(); - // http://stackoverflow.com/a/987376/5184751 - - try { - const selection = window.getSelection(); - const range = document.createRange(); - range.selectNodeContents(this.code); - selection.removeAllRanges(); - selection.addRange(range); - - const successful = document.execCommand('copy'); - selection.removeAllRanges(); - - // TODO: было бы ещё неплохо сделать какую-то анимацию, вроде "Скопировано", - // ибо сейчас после клика как-то неубедительно, скопировалось оно или нет - console.log('Copying text command was ' + (successful ? 'successful' : 'unsuccessful')); - } catch (err) {} - }; - - setCode = (el) => { - this.code = el; - }; - render() { - const {appName, code, displayCode, success} = this.props; + const {appName, code, state, displayCode, success} = this.props; const {isCopySupported} = this.state; + const authData = JSON.stringify({ + auth_code: code, + state: state + }); + + history.pushState(null, null, `#${authData}`); return (
+ + {success ? (
@@ -102,11 +87,36 @@ class Finish extends Component {
); } + + handleCopyClick = (event) => { + event.preventDefault(); + // http://stackoverflow.com/a/987376/5184751 + + try { + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(this.code); + selection.removeAllRanges(); + selection.addRange(range); + + const successful = document.execCommand('copy'); + selection.removeAllRanges(); + + // TODO: было бы ещё неплохо сделать какую-то анимацию, вроде "Скопировано", + // ибо сейчас после клика как-то неубедительно, скопировалось оно или нет + console.log('Copying text command was ' + (successful ? 'successful' : 'unsuccessful')); + } catch (err) {} + }; + + setCode = (el) => { + this.code = el; + }; } export default connect(({auth}) => ({ appName: auth.client.name, code: auth.oauth.code, displayCode: auth.oauth.displayCode, + state: auth.oauth.state, success: auth.oauth.success }))(Finish); From d19735b7e14326e2c293f2aba971308a8654c593 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 16 Mar 2016 07:03:23 +0200 Subject: [PATCH 12/15] =?UTF-8?q?=D0=A0=D0=B5=D1=81=D0=B5=D1=82=20=D1=81?= =?UTF-8?q?=D1=82=D0=B5=D0=B9=D1=82=D0=B0=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B2=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BC=20=D1=81=D0=BB=D1=83=D1=87=D0=B0=D0=B5,=20=D0=B5=D1=81?= =?UTF-8?q?=D0=BB=D0=B8=20=D1=8E=D0=B7=D0=B5=D1=80=20=D0=B7=D0=B0=D1=85?= =?UTF-8?q?=D0=BE=D1=82=D0=B5=D0=BB=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B9=D1=82?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/authFlow/AuthFlow.js | 5 +++++ src/services/authFlow/CompleteState.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/authFlow/AuthFlow.js b/src/services/authFlow/AuthFlow.js index 2dd239c..c2563e5 100644 --- a/src/services/authFlow/AuthFlow.js +++ b/src/services/authFlow/AuthFlow.js @@ -74,6 +74,11 @@ export default class AuthFlow { handleRequest(path, replace) { this.replace = replace; + if (path === '/') { + // reset oauth data if user tried to navigate to index route + this.run('setOAuthRequest', {}); + } + switch (path) { case '/oauth': this.setState(new OAuthState()); diff --git a/src/services/authFlow/CompleteState.js b/src/services/authFlow/CompleteState.js index 6bf47f8..273df5d 100644 --- a/src/services/authFlow/CompleteState.js +++ b/src/services/authFlow/CompleteState.js @@ -24,7 +24,7 @@ export default class CompleteState extends AbstractState { context.setState(new ActivationState()); } else if (user.shouldChangePassword) { context.setState(new ChangePasswordState()); - } else if (auth.oauth) { + } else if (auth.oauth && auth.oauth.clientId) { if (auth.oauth.code) { context.setState(new FinishState()); } else { From 7ce8637e3852fe512aa6489437eac4d75109775e Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 16 Mar 2016 07:34:18 +0200 Subject: [PATCH 13/15] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20passwordChange=20->=20ch?= =?UTF-8?q?angePassword?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/PanelTransition.jsx | 4 +-- .../ChangePassword.jsx} | 32 +++++++++++-------- .../ChangePassword.messages.js} | 4 +++ .../changePassword.scss} | 0 src/routes.js | 4 +-- src/services/authFlow/AuthFlow.js | 2 +- src/services/authFlow/ChangePasswordState.js | 2 +- 7 files changed, 29 insertions(+), 19 deletions(-) rename src/components/auth/{passwordChange/PasswordChange.jsx => changePassword/ChangePassword.jsx} (70%) rename src/components/auth/{passwordChange/PasswordChange.messages.js => changePassword/ChangePassword.messages.js} (87%) rename src/components/auth/{passwordChange/passwordChange.scss => changePassword/changePassword.scss} (100%) diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index ab15178..ca9eb0a 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -194,7 +194,7 @@ class PanelTransition extends Component { '/password': 1, '/activation': 1, '/oauth/permissions': -1, - '/password-change': 1, + '/change-password': 1, '/forgot-password': 1 }; const sign = map[key]; @@ -216,7 +216,7 @@ class PanelTransition extends Component { '/register': not('/activation') ? 'Y' : 'X', '/activation': not('/register') ? 'Y' : 'X', '/oauth/permissions': 'Y', - '/password-change': 'Y', + '/change-password': 'Y', '/forgot-password': not('/password') && not('/login') ? 'Y' : 'X' }; diff --git a/src/components/auth/passwordChange/PasswordChange.jsx b/src/components/auth/changePassword/ChangePassword.jsx similarity index 70% rename from src/components/auth/passwordChange/PasswordChange.jsx rename to src/components/auth/changePassword/ChangePassword.jsx index ec043f1..8eb9a2d 100644 --- a/src/components/auth/passwordChange/PasswordChange.jsx +++ b/src/components/auth/changePassword/ChangePassword.jsx @@ -5,15 +5,14 @@ import Helmet from 'react-helmet'; import buttons from 'components/ui/buttons.scss'; import { Input } from 'components/ui/Form'; - import BaseAuthBody from 'components/auth/BaseAuthBody'; -import passwordChangedMessages from './PasswordChange.messages'; - import icons from 'components/ui/icons.scss'; -import styles from './passwordChange.scss'; + +import messages from './ChangePassword.messages'; +import styles from './changePassword.scss'; class Body extends BaseAuthBody { - static displayName = 'PasswordChangeBody'; + static displayName = 'ChangePasswordBody'; render() { return ( @@ -25,40 +24,47 @@ class Body extends BaseAuthBody {

- +

- + + ); } } -export default function PasswordChange() { +export default function ChangePassword() { const componentsMap = { Title: () => ( // TODO: separate component for PageTitle - + {(msg) => {msg}} ), Body, Footer: () => ( ), Links: (props, context) => ( @@ -67,7 +73,7 @@ export default function PasswordChange() { context.reject(); }}> - + ) }; diff --git a/src/components/auth/passwordChange/PasswordChange.messages.js b/src/components/auth/changePassword/ChangePassword.messages.js similarity index 87% rename from src/components/auth/passwordChange/PasswordChange.messages.js rename to src/components/auth/changePassword/ChangePassword.messages.js index 566dce3..40b3659 100644 --- a/src/components/auth/passwordChange/PasswordChange.messages.js +++ b/src/components/auth/changePassword/ChangePassword.messages.js @@ -17,6 +17,10 @@ export default defineMessages({ id: 'change', defaultMessage: 'Change' }, + currentPassword: { + id: 'currentPassword', + defaultMessage: 'Enter current password' + }, newPassword: { id: 'newPassword', defaultMessage: 'Enter new password' diff --git a/src/components/auth/passwordChange/passwordChange.scss b/src/components/auth/changePassword/changePassword.scss similarity index 100% rename from src/components/auth/passwordChange/passwordChange.scss rename to src/components/auth/changePassword/changePassword.scss diff --git a/src/routes.js b/src/routes.js index 72f4931..d7f96e0 100644 --- a/src/routes.js +++ b/src/routes.js @@ -14,7 +14,7 @@ import Permissions from 'components/auth/permissions/Permissions'; import Activation from 'components/auth/activation/Activation'; import Password from 'components/auth/password/Password'; import Logout from 'components/auth/Logout'; -import PasswordChange from 'components/auth/passwordChange/PasswordChange'; +import ChangePassword from 'components/auth/changePassword/ChangePassword'; import ForgotPassword from 'components/auth/forgotPassword/ForgotPassword'; import Finish from 'components/auth/finish/Finish'; @@ -47,7 +47,7 @@ export default function routesFactory(store) { - + diff --git a/src/services/authFlow/AuthFlow.js b/src/services/authFlow/AuthFlow.js index c2563e5..66d87ae 100644 --- a/src/services/authFlow/AuthFlow.js +++ b/src/services/authFlow/AuthFlow.js @@ -96,7 +96,7 @@ export default class AuthFlow { case '/login': case '/password': case '/activation': - case '/password-change': + case '/change-password': case '/oauth/permissions': case '/oauth/finish': this.setState(new LoginState()); diff --git a/src/services/authFlow/ChangePasswordState.js b/src/services/authFlow/ChangePasswordState.js index 531ae7c..e2f8eab 100644 --- a/src/services/authFlow/ChangePasswordState.js +++ b/src/services/authFlow/ChangePasswordState.js @@ -3,7 +3,7 @@ import CompleteState from './CompleteState'; export default class ChangePasswordState extends AbstractState { enter(context) { - context.navigate('/password-change'); + context.navigate('/change-password'); } reject(context) { From 8e7fa33909959f11efe392fa97c481a793d8675c Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 16 Mar 2016 07:54:42 +0200 Subject: [PATCH 14/15] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B1=D0=B5=D0=BA=D0=B0=20=D1=81=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=BE=D0=B9=20=D1=81=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/actions.js | 31 ++++++++++++++++--- src/components/auth/authError/AuthError.jsx | 6 +++- .../auth/authError/AuthError.messages.js | 10 ++++++ .../auth/changePassword/ChangePassword.jsx | 3 ++ src/components/user/actions.js | 21 ++++++++++++- src/services/authFlow/ChangePasswordState.js | 5 +++ 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/components/auth/actions.js b/src/components/auth/actions.js index 70aa9fc..44c7175 100644 --- a/src/components/auth/actions.js +++ b/src/components/auth/actions.js @@ -1,6 +1,6 @@ import { routeActions } from 'react-router-redux'; -import { updateUser, logout as logoutUser, authenticate } from 'components/user/actions'; +import { updateUser, logout as logoutUser, changePassword as changeUserPassword, authenticate } from 'components/user/actions'; import request from 'services/request'; export function login({login = '', password = '', rememberMe = false}) { @@ -32,7 +32,7 @@ export function login({login = '', password = '', rememberMe = false}) { username: login, email: login })); - } else { + } else if (resp.errors) { if (resp.errors.login === LOGIN_REQUIRED && password) { dispatch(logout()); } @@ -46,6 +46,25 @@ export function login({login = '', password = '', rememberMe = false}) { ; } +export function changePassword({ + password = '', + newPassword = '', + newRePassword = '' +}) { + return (dispatch) => + dispatch(changeUserPassword({password, newPassword, newRePassword})) + .catch((resp) => { + if (resp.errors) { + const errorMessage = resp.errors[Object.keys(resp.errors)[0]]; + dispatch(setError(errorMessage)); + throw new Error(errorMessage); + } + + // TODO: log unexpected errors + }) + ; +} + export function register({ email = '', username = '', @@ -67,9 +86,11 @@ export function register({ dispatch(routeActions.push('/activation')); }) .catch((resp) => { - const errorMessage = resp.errors[Object.keys(resp.errors)[0]]; - dispatch(setError(errorMessage)); - throw new Error(errorMessage); + if (resp.errors) { + const errorMessage = resp.errors[Object.keys(resp.errors)[0]]; + dispatch(setError(errorMessage)); + throw new Error(errorMessage); + } // TODO: log unexpected errors }) diff --git a/src/components/auth/authError/AuthError.jsx b/src/components/auth/authError/AuthError.jsx index a8f7873..d1ec0d6 100644 --- a/src/components/auth/authError/AuthError.jsx +++ b/src/components/auth/authError/AuthError.jsx @@ -71,6 +71,10 @@ export default class AuthError extends Component { 'error.you_must_accept_rules': () => this.errorsMap['error.rulesAgreement_required'](), 'error.key_required': () => , 'error.key_is_required': () => this.errorsMap['error.key_required'](), - 'error.key_not_exists': () => + 'error.key_not_exists': () => , + + 'error.newPassword_required': () => , + 'error.newRePassword_required': () => , + 'error.newRePassword_does_not_match': () => }; } diff --git a/src/components/auth/authError/AuthError.messages.js b/src/components/auth/authError/AuthError.messages.js index bd0c397..7388ec8 100644 --- a/src/components/auth/authError/AuthError.messages.js +++ b/src/components/auth/authError/AuthError.messages.js @@ -31,6 +31,16 @@ export default defineMessages({ defaultMessage: 'Please enter password' }, + newPasswordRequired: { + id: 'newPasswordRequired', + defaultMessage: 'Please enter new password' + }, + + newRePasswordRequired: { + id: 'newRePasswordRequired', + defaultMessage: 'Please repeat new password' + }, + usernameRequired: { id: 'usernameRequired', defaultMessage: 'Username is required' diff --git a/src/components/auth/changePassword/ChangePassword.jsx b/src/components/auth/changePassword/ChangePassword.jsx index 8eb9a2d..6e0d3aa 100644 --- a/src/components/auth/changePassword/ChangePassword.jsx +++ b/src/components/auth/changePassword/ChangePassword.jsx @@ -30,6 +30,7 @@ class Body extends BaseAuthBody { @@ -46,6 +48,7 @@ class Body extends BaseAuthBody { diff --git a/src/components/user/actions.js b/src/components/user/actions.js index adbd142..2c26707 100644 --- a/src/components/user/actions.js +++ b/src/components/user/actions.js @@ -24,7 +24,6 @@ export function logout() { return setUser({isGuest: true}); } - export function fetchUserData() { return (dispatch) => request.get('/api/accounts/current') @@ -45,6 +44,26 @@ export function fetchUserData() { }); } +export function changePassword({ + password = '', + newPassword = '', + newRePassword = '' +}) { + return (dispatch) => + request.post( + '/api/accounts/change-password', + {password, newPassword, newRePassword} + ) + .then((resp) => { + dispatch(updateUser({ + shouldChangePassword: false + })); + + return resp; + }) + ; +} + export function authenticate(token) { if (!token || token.split('.').length !== 3) { diff --git a/src/services/authFlow/ChangePasswordState.js b/src/services/authFlow/ChangePasswordState.js index e2f8eab..45570b7 100644 --- a/src/services/authFlow/ChangePasswordState.js +++ b/src/services/authFlow/ChangePasswordState.js @@ -6,6 +6,11 @@ export default class ChangePasswordState extends AbstractState { context.navigate('/change-password'); } + resolve(context, payload) { + context.run('changePassword', payload) + .then(() => context.setState(new CompleteState())); + } + reject(context) { context.run('updateUser', { shouldChangePassword: false From 7ceba60bf78d2589b280d106a9cb1ec317d2a9f9 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 16 Mar 2016 07:59:16 +0200 Subject: [PATCH 15/15] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D0=BD=D0=B0=20=D0=B0=D0=BD=D0=B3=D0=BB=D0=B8?= =?UTF-8?q?=D0=B9=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B4=D0=BB=D1=8F=20finish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/finish/Finish.messages.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/auth/finish/Finish.messages.js b/src/components/auth/finish/Finish.messages.js index aacf2a2..6df00e2 100644 --- a/src/components/auth/finish/Finish.messages.js +++ b/src/components/auth/finish/Finish.messages.js @@ -3,22 +3,27 @@ import { defineMessages } from 'react-intl'; export default defineMessages({ authForAppSuccessful: { id: 'authForAppSuccessful', - defaultMessage: 'Авторизация для {appName} успешно выполнена' + defaultMessage: 'Authorization for {appName} was successfully completed' + // defaultMessage: 'Авторизация для {appName} успешно выполнена' }, authForAppFailed: { id: 'authForAppFailed', - defaultMessage: 'Авторизация для {appName} не удалась' + defaultMessage: 'Authorization for {appName} was failed' + // defaultMessage: 'Авторизация для {appName} не удалась' }, waitAppReaction: { id: 'waitAppReaction', - defaultMessage: 'Пожалуйста, дождитесь реакции вашего приложения' + defaultMessage: 'Please, wait till your application response' + // defaultMessage: 'Пожалуйста, дождитесь реакции вашего приложения' }, passCodeToApp: { id: 'passCodeToApp', - defaultMessage: 'Чтобы завершить процесс авторизации, пожалуйста, передай {appName} этот код' + defaultMessage: 'To complete authorization process, please, provide the following code to {appName}' + // defaultMessage: 'Чтобы завершить процесс авторизации, пожалуйста, передай {appName} этот код' }, copy: { id: 'copy', - defaultMessage: 'Скопировать' + defaultMessage: 'Copy' + // defaultMessage: 'Скопировать' } });