accounts-frontend/src/services/authFlow/AuthFlow.js

153 lines
4.3 KiB
JavaScript
Raw Normal View History

2016-03-02 02:06:14 +05:30
import { routeActions } from 'react-router-redux';
import RegisterState from './RegisterState';
import LoginState from './LoginState';
import OAuthState from './OAuthState';
import ForgotPasswordState from './ForgotPasswordState';
import RecoverPasswordState from './RecoverPasswordState';
import ResendActivationState from './ResendActivationState';
2016-03-02 02:06:14 +05:30
// TODO: a way to unload service (when we are on account page)
2016-03-02 02:06:14 +05:30
export default class AuthFlow {
constructor(actions) {
if (typeof actions !== 'object') {
throw new Error('AuthFlow requires an actions object');
}
this.actions = actions;
if (Object.freeze) {
Object.freeze(this.actions);
}
}
2016-03-02 02:06:14 +05:30
setStore(store) {
this.navigate = (route) => {
const {routing} = this.getState();
if (routing.location.pathname !== route) {
if (this.replace) {
this.replace(route);
}
store.dispatch(routeActions.push(route));
}
this.replace = null;
};
this.getState = store.getState.bind(store);
this.dispatch = store.dispatch.bind(store);
}
resolve(payload = {}) {
this.state.resolve(this, payload);
}
reject(payload = {}) {
this.state.reject(this, payload);
}
goBack() {
this.state.goBack(this);
}
run(actionId, payload) {
2016-05-30 09:53:27 +05:30
if (actionId === 'redirect') {
location.href = payload;
return;
}
if (!this.actions[actionId]) {
2016-03-02 02:06:14 +05:30
throw new Error(`Action ${actionId} does not exists`);
}
return this.dispatch(this.actions[actionId](payload));
2016-03-02 02:06:14 +05:30
}
setState(state) {
if (!state) {
throw new Error('State is required');
}
// if (this.state instanceof state.constructor) {
// // already in this state
// return;
// }
2016-03-02 02:06:14 +05:30
this.state && this.state.leave(this);
this.state = state;
const resp = this.state.enter(this);
if (resp && resp.then) {
// this is a state with an async enter phase
// block route components from mounting, till promise will be resolved
if (this.onReady) {
const callback = this.onReady;
this.onReady = () => {};
return resp.then(callback);
}
return resp;
}
2016-03-02 02:06:14 +05:30
}
/**
* This should be called from onEnter prop of react-router Route component
*
* @param {string} path
* @param {function} replace
* @param {function} [callback = function() {}] - an optional callback function to be called, when state will be stabilized
* (state's enter function's promise resolved)
*/
handleRequest(path, replace, callback = function() {}) {
2016-03-02 02:06:14 +05:30
this.replace = replace;
this.onReady = callback;
2016-03-02 02:06:14 +05:30
if (path === '/') {
// reset oauth data if user tried to navigate to index route
this.run('setOAuthRequest', {});
}
2016-05-28 03:54:22 +05:30
switch (path) { // use only first part of an url
2016-03-02 02:06:14 +05:30
case '/oauth':
this.setState(new OAuthState());
break;
case '/register':
this.setState(new RegisterState());
break;
case '/forgot-password':
this.setState(new ForgotPasswordState());
break;
case '/resend-activation':
this.setState(new ResendActivationState());
break;
case '/':
2016-03-02 02:06:14 +05:30
case '/login':
case '/password':
case '/activation':
case '/change-password':
2016-03-02 02:06:14 +05:30
case '/oauth/permissions':
case '/oauth/finish':
2016-03-02 02:06:14 +05:30
this.setState(new LoginState());
break;
default:
2016-05-28 03:54:22 +05:30
switch (path.replace(/(.)\/.+/, '$1')) { // use only first part of an url
case '/recover-password':
this.setState(new RecoverPasswordState());
break;
default:
throw new Error(`Unsupported request: ${path}`);
}
2016-03-02 02:06:14 +05:30
}
this.onReady();
2016-03-02 02:06:14 +05:30
}
}