import React, { ComponentType, FC, useContext } from 'react'; import { BlurCircular } from '@material-ui/icons'; import { NonAuthRoutes } from 'api/routes'; import { AuthContext } from 'components/AuthUser/AuthContext'; import { Unauthorized } from 'components/NonAuthUser/Unauthorized/Unauthorized'; import { useAuth } from 'hooks/useAuth'; import { useRole } from 'hooks/useRole'; import { Redirect } from 'react-router-dom'; const HandleIsAuth: FC<{ isAuth: boolean }> = ({ isAuth }) => isAuth ? ( <Unauthorized /> ) : ( <Redirect to={{ pathname: `${NonAuthRoutes.auth}${NonAuthRoutes.signIn}` }} /> ); interface WithAuthProps { allowedRoles: string[]; } interface Props extends WithAuthProps { children: React.ReactNode; } /* eslint-disable react/jsx-props-no-spreading */ /** * * @param WrappedComponent component to be wrapped by the authentication control. * This creates a "personal area" in the working implementation. * @returns {FC<T>} wrapped component. */ export const withAuthorization = <T extends WithAuthProps = WithAuthProps>( WrappedComponent: React.ComponentType<T>, ): FC<T> => { // Creating the inner component. The calculated Props type here is the where the magic happens. const ComponentWithAuthorization: FC<T> = ( props: Omit<T, keyof WithAuthProps>, ) => { const { allowedRoles } = props as T; const { role, isAuth } = useContext(AuthContext); console.log(`ROLE ${role} AUTH ${isAuth}`); // props comes afterwards so the can override the default ones. return allowedRoles.includes(role) && isAuth ? ( <WrappedComponent {...(props as T)} /> ) : ( <HandleIsAuth isAuth={isAuth} /> ); }; return ComponentWithAuthorization; };