I'm trying to implement private routes according user role permissions. Here is my code:
App.js
or routes.js
:
<PrivateRoutes path="/equipments" role="hasEquipments" component={(props) => <EquipmentsList {...props} />} />
<PrivateRoutes path="/users/options" role="hasUsers" component={(props) => <UsersOptions {...props} />} />
PrivateRoutes component:
const PrivateRoutes = ({ role, ...rest }) => {
const [permissions, setPermissions] = useState(false);
const user = JSON.parse(localStorage.getItem('@TEST:userInfo'));
useEffect(() => {
async function loadRoles() {
try {
if (user !== undefined) {
const response = await api.get(`/users/role/${user.nickname}`);
const userPermissions = response.data.permissions;
if (role === undefined) {
setPermissions(false);
}
if (role === 'hasEquipments') {
if (userPermissions.hasEquipments.state) {
setPermissions(true);
}
}
if (role === 'hasUsers') {
if (userPermissions.hasUsers.state) {
setPermissions(true);
}
}
}
} catch (err) {
console.log(err);
}
}
loadRoles();
}, [role]);
const userLogged = () => {
if (localStorage.getItem('@TEST:tokenJwt')) {
return true;
} else {
return false;
}
}
if (!userLogged()) {
return <Redirect to="/" />;
}
if (!role && userLogged()) {
return <Route {...rest} />;
}
return (
<>
{console.log(permissions)}
{permissions ? <Route {...rest} /> : <Redirect to="/" />}
</>
)
};
export default PrivateRoutes;
response.data
e.g. from /users/role/${user.nickname}
post:
{
hasEquipments: {
actions: {post: true, put: true, delete:: false}
state: true,
},
hasUsers: {
actions: {post: false, put: false, delete:: false}
state: false,
}
}
Following the response.data
e.g, i would have access of /equipments
path.
No matter what, i'm always redirect to '/'
, permissions hook is always false
. In last return
, if i only print {console.log(permissions)}
, commenting {permissions ? <Route {...rest} /> : <Redirect to="/" />}
line, then permissions hook is true
. I think i'm misunderstading some lifecycle concepts here.
Any tips how to achieve this?
The redirection is made even before the call to the api is made. useEffect
is called after the component has rendered. A solution would be to add an intermediary value, like null
or you let it undefined, it's just a way to know whether the call to the api has already been made or not.
const [permissions, setPermissions] = useState(null);
// ...
if (permissions === null) return null
// ...
{permissions ? <Route {...rest} /> : <Redirect to="/" />}