diff --git a/frontend/client/Routes.tsx b/frontend/client/Routes.tsx index 6c11d0cf..ed7b892e 100644 --- a/frontend/client/Routes.tsx +++ b/frontend/client/Routes.tsx @@ -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, }, }, { diff --git a/frontend/client/components/AuthRoute.tsx b/frontend/client/components/AuthRoute.tsx index 62dbe1e6..7441d036 100644 --- a/frontend/client/components/AuthRoute.tsx +++ b/frontend/client/components/AuthRoute.tsx @@ -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 { + 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 ; + return ; } if ((user && !onlyLoggedOut) || (!user && onlyLoggedOut)) { return ; } 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 ; + let newLocation = { ...location, pathname: '/auth' }; + if (onlyLoggedOut) { + newLocation = authForwardLocation || { ...location, pathname: '/profile' }; + } + return ; } } + 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( + (state: AppState) => ({ + user: state.auth.user, + isCheckingUser: state.auth.isCheckingUser, + hasCheckedUser: state.auth.hasCheckedUser, + authForwardLocation: state.auth.authForwardLocation, + }), + { setAuthForwardLocation: authActions.setAuthForwardLocation }, +)(AuthRoute); diff --git a/frontend/client/components/Template/index.tsx b/frontend/client/components/Template/index.tsx index 034f74fe..8ad5a45b 100644 --- a/frontend/client/components/Template/index.tsx +++ b/frontend/client/components/Template/index.tsx @@ -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 { +export default class Template extends React.PureComponent { 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 = ( -
- Login required.
TODO: links or redirect -
- ); - } - } + const content = children; + const isCentered = false; const className = classnames( 'Template', @@ -65,9 +40,3 @@ class Template extends React.PureComponent { ); } } - -export default connect(state => { - return { - authUser: state.auth.user, - }; -})(Template); diff --git a/frontend/client/modules/auth/actions.ts b/frontend/client/modules/auth/actions.ts index 5f4bb944..cf0c2285 100644 --- a/frontend/client/modules/auth/actions.ts +++ b/frontend/client/modules/auth/actions.ts @@ -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 }, + }; +} diff --git a/frontend/client/modules/auth/reducers.ts b/frontend/client/modules/auth/reducers.ts index 4b07710d..66fdff5c 100644 --- a/frontend/client/modules/auth/reducers.ts +++ b/frontend/client/modules/auth/reducers.ts @@ -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; } diff --git a/frontend/client/modules/auth/types.ts b/frontend/client/modules/auth/types.ts index f68f1043..17743547 100644 --- a/frontend/client/modules/auth/types.ts +++ b/frontend/client/modules/auth/types.ts @@ -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;