It's the first time I am working with role based routes. We have a fully working app for players. Now, we need to add Trainer page for that app. We store the users in Firebase all we need to add new key for users something like trainer: true|false
manually. And in React Application we will redirect the users.
For example:
if (user.trainer) {
<Redirect to={"/trainer"}
} else {
<Redirect to={"/"}
}
And we need to manage other pages. For example: when trainers want to navigate to another pages where it's not allowed we need to redirect them back to "/trainer"
or the opposite normal player can't navigate to "/trainer"
page. Can someone please help me with that ?
I have centralized routes like this;
import SignInSignUp from "./pages/SignInSignUp/SignInSignUp";
import Home from "./pages/Home/Home";
import Help from "./pages/Help/Help";
import Profile from "./pages/Profile/Profile";
import Exercises from "./pages/Exercises/Exercises";
import Trainer from "./pages/Trainer/Trainer";
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer },
];
And I loop the routes like that;
import "./App.scss";
import { Switch, Route, Redirect } from "react-router-dom";
import Navbar from "./components/Navbar/Navbar";
import ProtectedRouter from "./utils/ProtectedRouter";
import { routes, navbarPaths } from "./routes";
function App() {
return (
<div className="App">
<Switch>
{routes.map(
({
isProtected,
component,
path,
}: {
isProtected: boolean;
component: any;
path: string;
}) => {
const RouteWrapper = isProtected ? ProtectedRouter : Route;
return (
<RouteWrapper
exact
key={path}
path={path}
component={component}
/>
);
}
)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}
export default App;
And this is my Protected Route Component
import { Route, Redirect } from "react-router-dom";
import { useAuthStatus } from "../firebase/useAuthStatus.hook";
const ProtectedRouter = ({ component: Component, ...rest }: any) => {
const { loggedIn, checkingStatus } = useAuthStatus();
return (
<Route
{...rest}
render={(props) => {
if (!checkingStatus) {
if (loggedIn) {
return <Component />;
} else {
return (
<Redirect
to={{
pathname: "/auth",
state: {
from: props.location,
},
}}
/>
);
}
}
}}
/>
);
};
export default ProtectedRouter;
If I'm understanding your question correctly, you want to conditionally change the redirect target in your ProtectedRouter
component based on a user's role.
Not tested at all, but I believe the following will resolve your question.
Refactor your ProtectedRoute
to take the isProtected
, trainer
, and passed route props. If the route is unprotected, check the user's trainer
role for a match and conditionally render a route or redirect to "/trainer"
or "/"
. If the route is protected and the user is authenticated, again check the user's trainer
role for a match and conditionally render a route or redirect to "/trainer"
or "/"
.
const ProtectedRouter = ({ isProtected, trainer, ...props }: any) => {
const location = useLocation();
const { loggedIn, checkingStatus } = useAuthStatus();
const user = /* business logic to get user object */
if (checkingStatus) return null;
if (!isProtected || loggedIn) {
return user.trainer === trainer
? <Route {...props} />
: <Redirect to={user.trainer ? "/trainer" : "/"} />;
}
return (
<Redirect
to={{
pathname: "/auth",
state: { from: location },
}}
/>
);
};
Update the routes
to add a trainer
property.
export const routes = [
{ isProtected: false, path: "/auth", component: SignInSignUp },
{ isProtected: true, path: "/", component: Home },
{ isProtected: true, path: "/help", component: Help },
{ isProtected: true, path: "/profile", component: Profile },
{ isProtected: true, path: "/exercises", component: Exercises },
{ isProtected: true, path: "/trainer", component: Trainer, trainer: true },
];
Update App
to map all the routes to the custom route component.
function App() {
...
return (
<div className="App">
<Switch>
{routes.map(props => <ProtectedRouter key={props.path} exact {...props} />)}
<Route exact path="/player*" render={() => (<Redirect to={"/"} />)} />
</Switch>
<Route path={navbarPaths} exact component={Navbar} />
</div>
);
}