mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Redirect users to correct location after login (#316)
This commit is contained in:
parent
1597ad23a4
commit
b57514e9d2
7 changed files with 95 additions and 4 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
19
frontend/redux/nodes/redirectLocation/actions.js
Normal file
19
frontend/redux/nodes/redirectLocation/actions.js
Normal 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,
|
||||
};
|
||||
18
frontend/redux/nodes/redirectLocation/reducer.js
Normal file
18
frontend/redux/nodes/redirectLocation/reducer.js
Normal 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;
|
||||
28
frontend/redux/nodes/redirectLocation/reducer.tests.js
Normal file
28
frontend/redux/nodes/redirectLocation/reducer.tests.js
Normal 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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue