Redirect users to correct location after login (#316)

This commit is contained in:
Mike Stone 2016-10-17 09:27:22 -04:00 committed by GitHub
parent 1597ad23a4
commit b57514e9d2
7 changed files with 95 additions and 4 deletions

View file

@ -2,13 +2,16 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { isEqual } from 'lodash';
import { push } from 'react-router-redux';
import paths from '../../router/paths';
import { setRedirectLocation } from '../../redux/nodes/redirectLocation/actions';
export class AuthenticatedRoutes extends Component {
static propTypes = {
children: PropTypes.element,
dispatch: PropTypes.func,
loading: PropTypes.bool.isRequired,
locationBeforeTransitions: PropTypes.object,
user: PropTypes.object,
};
@ -35,9 +38,10 @@ export class AuthenticatedRoutes extends Component {
}
redirectToLogin = () => {
const { dispatch } = this.props;
const { dispatch, locationBeforeTransitions } = this.props;
const { LOGIN } = paths;
dispatch(setRedirectLocation(locationBeforeTransitions));
return dispatch(push(LOGIN));
}
@ -63,8 +67,9 @@ export class AuthenticatedRoutes extends Component {
const mapStateToProps = (state) => {
const { loading, user } = state.auth;
const { locationBeforeTransitions } = state.routing;
return { loading, user };
return { loading, locationBeforeTransitions, user };
};
export default connect(mapStateToProps)(AuthenticatedRoutes);

View file

@ -30,6 +30,9 @@ describe('AuthenticatedRoutes - component', () => {
force_password_reset: false,
},
},
routing: {
locationBeforeTransitions: {},
},
};
const storeWithUserRequiringPwReset = {
auth: {
@ -40,18 +43,27 @@ describe('AuthenticatedRoutes - component', () => {
force_password_reset: true,
},
},
routing: {
locationBeforeTransitions: {},
},
};
const storeWithoutUser = {
auth: {
loading: false,
user: null,
},
routing: {
locationBeforeTransitions: {},
},
};
const storeLoadingUser = {
auth: {
loading: true,
user: null,
},
routing: {
locationBeforeTransitions: {},
},
};
it('renders if there is a user in state', () => {

View file

@ -3,7 +3,9 @@ import { connect } from 'react-redux';
import { includes } from 'lodash';
import { push } from 'react-router-redux';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import { clearAuthErrors, loginUser } from '../../redux/nodes/auth/actions';
import { clearRedirectLocation } from '../../redux/nodes/redirectLocation/actions';
import debounce from '../../utilities/debounce';
import LoginForm from '../../components/forms/LoginForm';
import LoginSuccessfulPage from '../LoginSuccessfulPage';
@ -18,6 +20,7 @@ export class LoginPage extends Component {
error: PropTypes.string,
loading: PropTypes.bool,
pathname: PropTypes.string,
redirectLocation: PropTypes.object,
user: PropTypes.object,
};
@ -46,14 +49,16 @@ export class LoginPage extends Component {
};
onSubmit = debounce((formData) => {
const { dispatch } = this.props;
const { dispatch, redirectLocation } = this.props;
const { HOME } = paths;
const redirectTime = 1500;
return dispatch(loginUser(formData))
.then(() => {
this.setState({ loginVisible: false });
setTimeout(() => {
return dispatch(push(HOME));
const nextLocation = redirectLocation || HOME;
dispatch(clearRedirectLocation);
return dispatch(push(nextLocation));
}, redirectTime);
});
})
@ -104,10 +109,12 @@ export class LoginPage extends Component {
const mapStateToProps = (state) => {
const { error, loading, user } = state.auth;
const { redirectLocation } = state;
return {
error,
loading,
redirectLocation,
user,
};
};

View file

@ -0,0 +1,19 @@
export const CLEAR_REDIRECT_LOCATION = 'CLEAR_REDIRECT_LOCATION';
export const SET_REDIRECT_LOCATION = 'SET_REDIRECT_LOCATION';
export const clearRedirectLocation = { type: CLEAR_REDIRECT_LOCATION };
export const setRedirectLocation = (redirectLocation) => {
return {
type: SET_REDIRECT_LOCATION,
payload: {
redirectLocation,
},
};
};
export default {
CLEAR_REDIRECT_LOCATION,
clearRedirectLocation,
SET_REDIRECT_LOCATION,
setRedirectLocation,
};

View file

@ -0,0 +1,18 @@
import { CLEAR_REDIRECT_LOCATION, SET_REDIRECT_LOCATION } from './actions';
export const initialState = null;
const reducer = (state = initialState, { type, payload }) => {
switch (type) {
case CLEAR_REDIRECT_LOCATION:
return null;
case SET_REDIRECT_LOCATION:
return {
...payload.redirectLocation,
};
default:
return state;
}
};
export default reducer;

View file

@ -0,0 +1,28 @@
import expect from 'expect';
import actions from './actions';
import reducer, { initialState } from './reducer';
describe('redirectLocation - reducer', () => {
const redirectObject = { action: 'PUSH', pathname: 'admin' };
const redirectAction = actions.setRedirectLocation(redirectObject);
it('sets the initial state', () => {
const newState = reducer(undefined, { type: 'RANDOM_ACTION' });
expect(newState).toEqual(initialState);
});
it('sets the redirect location in state', () => {
const newState = reducer(initialState, redirectAction);
expect(newState).toEqual(redirectObject);
});
it('clears the direction location in state', () => {
const state = reducer(initialState, redirectAction);
const newState = reducer(state, actions.clearRedirectLocation);
expect(newState).toEqual(null);
});
});

View file

@ -5,6 +5,7 @@ import auth from './nodes/auth/reducer';
import components from './nodes/components/reducer';
import entities from './nodes/entities/reducer';
import notifications from './nodes/notifications/reducer';
import redirectLocation from './nodes/redirectLocation/reducer';
export default combineReducers({
app,
@ -12,5 +13,6 @@ export default combineReducers({
components,
entities,
notifications,
redirectLocation,
routing: routerReducer,
});