0

I am new to nextJS, and I want to create a role-based application I have used the App route with nextJS's latest version(13.4) in that application, So that I did the role-based authentication using a higher-order component, In my scenario when an unauthorized person wants to access the unauthorized page I navigate the user into a permission-denied page, But before navigation, the page that user wants access will appear just a second, in order to prevent that, I have used the loader. But I don't know if the loader only prevents this type of issue or if any other methods have. Is the loader approach appropriate for handling unauthorized page access?

Higher Order Component

import React, { useEffect } from "react";
import { useRouter, usePathname } from "next/navigation";
import roles from "@/utils/routs";
import { isLoginReducer } from "@/redux/features/authSlice";
import { useDispatch, useSelector } from "react-redux";
import Loader from "@/components/elements/Loader";

const UseRoleHook = (Component: any) => {
  return function ProtectedRoute() {
    // Get user role and login status from Redux store
    const { role, isLogin } = useSelector(
      (state: { authPersistedReducer: { role: string; isLogin: boolean } }) =>
        state.authPersistedReducer
    );

    const dispatch = useDispatch();
    const pathname = usePathname();
    const router = useRouter();

    useEffect(() => {
      // Check if the user is not logged in
      if (!isLogin) {
        // If the role is "admin", "superAdmin", or "user", set login status to true and redirect to the home page
        if (role === "admin" || role === "superAdmin" || role === "user") {
          dispatch(isLoginReducer(true)); // Dispatch the action to update the login state
          router.push("/");
        } else {
          router.push("/login"); // Redirect the user to the login page if the role is not recognized
        }
      } else {
        // If the user is logged in
        // Check if the current pathname is allowed for the user's role
        if (!roles[role]?.path.includes(pathname)) {
          // If not allowed, throw an error indicating "Permission Denied"
          throw new Error("Permission Denied");
        } else {
          // If allowed, redirect the user to the current pathname
          router.push(pathname);
        }
      }
    }, [isLogin, role, pathname]);

    if (!roles[role]?.path.includes(pathname)) {
      // If not, return a loading spinner using the Loader component while the correct route is loaded
      return (
        // Or display a loading spinner or message
        <div className="w-full h-screen flex justify-center items-center">
          <Loader />
        </div>
      );
    }

    return <Component />;
  };
};

export default UseRoleHook;

Gibson
  • 82
  • 7

1 Answers1

0

You're using useEffect hook and it is asynchronous in nature. You should use useLayoutEffect hook which is synchronous in nature. When you authenticate the user it will stop to return the JSX unless until user is confirmed.

Kannu Mandora
  • 479
  • 2
  • 10
  • Thanks for your suggestion, but this approach didn't work as I expected. And this approach also gives the same issue. – Gibson Jul 05 '23 at 17:38