import React, { useState, useEffect, useContext } from 'react'; import axios from 'axios'; import { Route, Redirect, RouteProps } from 'react-router-dom'; import { NonAuthRoutes } from 'api/routes'; import { AuthContext } from 'components/AuthUser/AuthContext'; /** * A wrapper for <Route> that redirects to the login screen if you're not yet authenticated. * Every non-public route must be wrapped with this component. * */ type Props = { Component: React.FC<RouteProps>; path: string; requiredRoles: string[]; }; /* eslint-disable react/jsx-props-no-spreading */ export const PrivateRoute = ({ Component, path, requiredRoles, }: Props): JSX.Element => { const [auth, setAuth] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false); const { role } = useContext(AuthContext); useEffect(() => { const fetch = async (): Promise<unknown> => { const result = await axios('/api/web/login/is_authenticated'); setAuth(result.data.is_authenticated); setLoading(true); return null; }; /* Check if user is logged in. Avoiding this condition would call is\_authenticated every time this component state is triggered, falling in unnecessary calls to the server. */ if (role) fetch(); }, [auth]); const userHasRequiredRole = requiredRoles.includes(role); const message = userHasRequiredRole ? 'Please log in to view this page' : 'Your role is not allowed'; return ( <Route exact={false} path={path} render={(props: RouteProps) => auth && userHasRequiredRole ? ( <Component {...props} /> ) : ( <Redirect to={{ pathname: userHasRequiredRole ? `auth/${NonAuthRoutes.signIn}` : NonAuthRoutes.unauthorized, state: { message, requestedPath: path, }, }} /> ) } /> ); };