diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index 4f438ff..316a7d3 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -323,9 +323,15 @@ class PanelTransition extends Component { } getHeader({key, style, data}) { - const {Title, hasBackButton} = data; + const {Title} = data; const {transformSpring} = style; + let {hasBackButton} = data; + + if (typeof hasBackButton === 'function') { + hasBackButton = hasBackButton(this.props); + } + style = { ...this.getDefaultTransitionStyles(key, style), opacity: 1 // reset default diff --git a/src/components/auth/actions.js b/src/components/auth/actions.js index e5a47af..427f442 100644 --- a/src/components/auth/actions.js +++ b/src/components/auth/actions.js @@ -1,6 +1,7 @@ import { routeActions } from 'react-router-redux'; import logger from 'services/logger'; +import history from 'services/history'; import { updateUser, acceptRules as userAcceptRules } from 'components/user/actions'; import { authenticate, logoutAll } from 'components/accounts/actions'; import authentication from 'services/api/authentication'; @@ -11,6 +12,25 @@ import dispatchBsod from 'components/ui/bsod/dispatchBsod'; export { updateUser } from 'components/user/actions'; export { authenticate, logoutAll as logout } from 'components/accounts/actions'; +/** + * Reoutes user to the previous page if it is possible + * + * @param {string} fallbackUrl - an url to route user to if goBack is not possible + * + * @return {object} - action definition + */ +export function goBack(fallbackUrl = null) { + if (history.canGoBack()) { + return routeActions.goBack(); + } else if (fallbackUrl) { + return routeActions.push(fallbackUrl); + } + + return { + type: 'noop' + }; +} + export function login({login = '', password = '', rememberMe = false}) { const PASSWORD_REQUIRED = 'error.password_required'; const LOGIN_REQUIRED = 'error.login_required'; diff --git a/src/components/auth/login/LoginBody.jsx b/src/components/auth/login/LoginBody.jsx index a5de8a9..c6b1171 100644 --- a/src/components/auth/login/LoginBody.jsx +++ b/src/components/auth/login/LoginBody.jsx @@ -1,5 +1,3 @@ -import React from 'react'; - import { Input } from 'components/ui/form'; import BaseAuthBody from 'components/auth/BaseAuthBody'; @@ -8,6 +6,9 @@ import messages from './Login.intl.json'; export default class LoginBody extends BaseAuthBody { static displayName = 'LoginBody'; static panelId = 'login'; + static hasGoBack = (state) => { + return !state.user.isGuest; + }; autoFocusField = 'login'; diff --git a/src/index.js b/src/index.js index 827f62c..3679dd6 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,9 @@ import storeFactory from 'storeFactory'; import bsodFactory from 'components/ui/bsod/factory'; import loader from 'services/loader'; import logger from 'services/logger'; +import history from 'services/history'; + +history.init(); logger.init({ sentryCdn: window.SENTRY_CDN diff --git a/src/services/authFlow/LoginState.js b/src/services/authFlow/LoginState.js index 04161c6..991790c 100644 --- a/src/services/authFlow/LoginState.js +++ b/src/services/authFlow/LoginState.js @@ -7,15 +7,16 @@ export default class LoginState extends AbstractState { enter(context) { const {auth, user} = context.getState(); + const isUserAddsSecondAccount = !user.isGuest + && /login|password/.test(context.getRequest().path); // TODO: improve me + // TODO: it may not allow user to leave password state till he click back or enters password if (auth.login) { context.setState(new PasswordState()); - } else if (user.isGuest - // for the case, when user is logged in and wants to add a new aacount - || /login|password/.test(context.getRequest().path) // TODO: improve me - ) { + } else if (user.isGuest || isUserAddsSecondAccount) { context.navigate('/login'); } else { + // can not detect needed state. Delegating decision to the next state context.setState(new PasswordState()); } } @@ -25,4 +26,8 @@ export default class LoginState extends AbstractState { .then(() => context.setState(new PasswordState())) .catch((err = {}) => err.errors || logger.warn(err)); } + + goBack(context) { + context.run('goBack', '/'); + } } diff --git a/src/services/history.js b/src/services/history.js new file mode 100644 index 0000000..a8712e1 --- /dev/null +++ b/src/services/history.js @@ -0,0 +1,17 @@ +/** + * A helper wrapper service around window.history + */ + +export default { + init() { + this.initialLength = window.history.length; + }, + + /** + * @return {bool} - whether history.back() can be safetly called + */ + canGoBack() { + return document.referrer.includes(`${location.protocol}//${location.host}`) + || this.initialLength < window.history.length; + } +} diff --git a/tests/services/authFlow/LoginState.test.js b/tests/services/authFlow/LoginState.test.js index 4688559..0e91f2c 100644 --- a/tests/services/authFlow/LoginState.test.js +++ b/tests/services/authFlow/LoginState.test.js @@ -81,4 +81,12 @@ describe('LoginState', () => { return promise.catch(mock.verify.bind(mock)); }); }); + + describe('#goBack', () => { + it('should return to previous page', () => { + expectRun(mock, 'goBack', '/'); + + state.goBack(context); + }); + }); });