location forward after authentication (#90)

This commit is contained in:
AMStrix 2019-01-18 00:40:30 -06:00 committed by William O'Beirne
parent 9829f3f1ea
commit c8ab0d0f37
6 changed files with 86 additions and 57 deletions

View File

@ -64,7 +64,6 @@ const routeConfigs: RouteConfig[] = [
},
template: {
title: 'Create a Proposal',
requiresAuth: true,
},
onlyLoggedIn: true,
},
@ -77,7 +76,6 @@ const routeConfigs: RouteConfig[] = [
},
template: {
title: 'Browse proposals',
requiresAuth: false,
},
},
{
@ -90,7 +88,6 @@ const routeConfigs: RouteConfig[] = [
title: 'Edit proposal',
isFullScreen: true,
hideFooter: true,
requiresAuth: true,
},
onlyLoggedIn: true,
},
@ -102,7 +99,6 @@ const routeConfigs: RouteConfig[] = [
},
template: {
title: 'Proposal',
requiresAuth: false,
},
},
{

View File

@ -1,38 +1,81 @@
import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { Spin } from 'antd';
import { Spin, message } from 'antd';
import { AppState } from 'store/reducers';
interface StateProps {
user: AppState['auth']['user'];
isCheckingUser: AppState['auth']['isCheckingUser'];
}
import { authActions } from 'modules/auth';
interface OwnProps {
onlyLoggedOut?: boolean;
}
type Props = RouteProps & StateProps & OwnProps;
interface StateProps {
user: AppState['auth']['user'];
isCheckingUser: AppState['auth']['isCheckingUser'];
hasCheckedUser: AppState['auth']['hasCheckedUser'];
authForwardLocation: AppState['auth']['authForwardLocation'];
}
interface DispatchProps {
setAuthForwardLocation: typeof authActions['setAuthForwardLocation'];
}
type Props = RouteProps & StateProps & OwnProps & DispatchProps;
class AuthRoute extends React.Component<Props> {
componentDidMount() {
this.setAuthForward();
}
componentDidUpdate(prevProps: Props) {
const { hasCheckedUser } = this.props;
// in case we mounted before having checked user
if (!prevProps.hasCheckedUser && hasCheckedUser) {
this.setAuthForward();
}
}
public render() {
const { user, onlyLoggedOut, isCheckingUser, location, ...routeProps } = this.props;
const {
user,
onlyLoggedOut,
isCheckingUser,
location,
authForwardLocation,
...routeProps
} = this.props;
if (isCheckingUser) {
return <Spin />;
return <Spin tip="Checking authentication status" />;
}
if ((user && !onlyLoggedOut) || (!user && onlyLoggedOut)) {
return <Route {...routeProps} />;
} else {
// TODO: redirect to desired destination after auth
// TODO: Show alert that claims they need to be logged in
const pathname = onlyLoggedOut ? '/profile' : '/auth';
return <Redirect to={{ ...location, pathname }} />;
let newLocation = { ...location, pathname: '/auth' };
if (onlyLoggedOut) {
newLocation = authForwardLocation || { ...location, pathname: '/profile' };
}
return <Redirect to={{ ...newLocation }} />;
}
}
private setAuthForward = () => {
const {
setAuthForwardLocation,
location,
hasCheckedUser,
user,
onlyLoggedOut,
} = this.props;
if (hasCheckedUser && !user && !onlyLoggedOut) {
message.warn('Authorization required.');
setAuthForwardLocation(location);
}
};
}
export default connect((state: AppState) => ({
user: state.auth.user,
isCheckingUser: state.auth.isCheckingUser,
}))(AuthRoute);
export default connect<StateProps, DispatchProps, OwnProps, AppState>(
(state: AppState) => ({
user: state.auth.user,
isCheckingUser: state.auth.isCheckingUser,
hasCheckedUser: state.auth.hasCheckedUser,
authForwardLocation: state.auth.authForwardLocation,
}),
{ setAuthForwardLocation: authActions.setAuthForwardLocation },
)(AuthRoute);

View File

@ -1,51 +1,26 @@
import React from 'react';
import { connect } from 'react-redux';
import { Layout } from 'antd';
import classnames from 'classnames';
import BasicHead from 'components/BasicHead';
import Header from 'components/Header';
import Footer from 'components/Footer';
import { AppState } from 'store/reducers';
import './index.less';
interface StateProps {
authUser: AppState['auth']['user'];
}
export interface TemplateProps {
title: string;
isHeaderTransparent?: boolean;
isFullScreen?: boolean;
hideFooter?: boolean;
requiresAuth?: boolean;
}
type Props = StateProps & TemplateProps;
type Props = TemplateProps;
class Template extends React.PureComponent<Props> {
export default class Template extends React.PureComponent<Props> {
render() {
const {
children,
title,
isHeaderTransparent,
isFullScreen,
hideFooter,
requiresAuth,
authUser,
} = this.props;
const { children, title, isHeaderTransparent, isFullScreen, hideFooter } = this.props;
let content = children;
let isCentered = false;
if (requiresAuth) {
if (!authUser) {
isCentered = true;
content = (
<div>
Login required. <br /> TODO: links or redirect
</div>
);
}
}
const content = children;
const isCentered = false;
const className = classnames(
'Template',
@ -65,9 +40,3 @@ class Template extends React.PureComponent<Props> {
);
}
}
export default connect<StateProps, {}, TemplateProps, AppState>(state => {
return {
authUser: state.auth.user,
};
})(Template);

View File

@ -1,6 +1,7 @@
import types from './types';
import { Dispatch } from 'redux';
import * as Sentry from '@sentry/browser';
import { RouteProps } from 'react-router-dom';
import {
createUser as apiCreateUser,
checkUserAuth,
@ -96,3 +97,10 @@ export function logout() {
});
};
}
export function setAuthForwardLocation(location: RouteProps['location']) {
return {
type: types.SET_AUTH_FORWARD_LOCATION,
payload: { location },
};
}

View File

@ -1,12 +1,15 @@
import types from './types';
import usersTypes from 'modules/users/types';
import { User, AuthSignatureData } from 'types';
import { RouteProps } from 'react-router-dom';
export interface AuthState {
user: User | null;
isAuthingUser: boolean;
authUserError: string | null;
authForwardLocation: RouteProps['location'];
isCheckingUser: boolean;
hasCheckedUser: boolean;
@ -24,6 +27,8 @@ export const INITIAL_STATE: AuthState = {
isAuthingUser: false,
authUserError: null,
authForwardLocation: undefined,
isCreatingUser: false,
createUserError: null,
@ -135,6 +140,12 @@ export default function createReducer(
...state,
user: null,
};
case types.SET_AUTH_FORWARD_LOCATION:
return {
...state,
authForwardLocation: action.payload.location,
};
}
return state;
}

View File

@ -23,6 +23,8 @@ enum AuthTypes {
LOGOUT_PENDING = 'LOGOUT_PENDING',
LOGOUT_FULFILLED = 'LOGOUT_FULFILLED',
LOGOUT_REJECTED = 'LOGOUT_REJECTED',
SET_AUTH_FORWARD_LOCATION = 'SET_AUTH_FORWARD_LOCATION',
}
export default AuthTypes;