Search code examples
reactjsreact-routersupabasereact-query

after making the routes protected, I got stuck in the login page although the login was successful


I'm protecting my routes using <ProtectedRoutes/>, the scenario is to navigate the user after the successful login to the /dashboard, the problem is no matter how many times I loged in successfully, the browser's URL changed to /dashboard for less than a second then go back to /login page again. I got the object that contains all the information of the authenticated user from supabase.

here are my routes, I made all the routes as children to the <ProtectedRoutes/>:

const router = createBrowserRouter([
  {
    element: <ProtectedRoutes/>,
    children: [
      {
        element: <AppLayouts />,
        children: [
          {
            path: "/",
            element: <Navigate to="/dashboard" replace />,
          },
          {
            path: "/dashboard",
            element: <Dashboard />,
          },
          {
            path: "/users",
            element: <NewUsers />,
          },
          {
            path: "/account",
            element: <Account />,
          },
          {
            path: "/bookings",
            element: <Bookings />,
          },
          {
            path: "/bookings/:id",
            element: <OneBookingDetails/>,
          },
          {
            path: "/checkin/:id",
            element: <Checkin/>,
          },
          {
            path: "/cabins",
            element: <Cabins />,
          },
          {
            path: "/settings",
            element: <Settings />,
          },
        ],
      },
      ]
  },
 
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "*",
    element: <PageNotFound />,
  },
]);

ProtectedRoutes:

export default function ProtectedRoutes({children}) {
    const navigate = useNavigate();
    
    // 1) load the authenticated User:
    const {isAuthenticated, isLoading} = useUser();
    useEffect(function(){
        // 3) not an authenticaed user? then redirect to the login page
        if(!isAuthenticated && !isLoading) navigate("/login");
    }, [isAuthenticated, isLoading, navigate]);

    // 2) show a spinner while the process of checking is taking place:
    if(isLoading) return <SpinnerContainer><Spinner/></SpinnerContainer>


    // 4) an authenticated user? render the app (children):
    if(isAuthenticated) return children;
}

useUser hook:

    import { useQuery } from "@tanstack/react-query";

import { getCurrentUser } from "../../services/apiAuth";

    export async function useUser() {
        const {isLoading, data: user, fetchStatus} = useQuery({
            queryKey: ["user"],
            queryFn: getCurrentUser
        });
    
        return {isLoading, fetchStatus, user, isAuthenticated: user?.role === "authenticated"};
    }

the useLogin hook, which is responsible for the navigation to the /dashboard (note that I got toast.success("Welcome Back!"); after each login process:

import { useMutation } from "@tanstack/react-query";
import { login as loginApi } from "../../services/apiAuth";
import { useNavigate } from "react-router-dom";
import toast from "react-hot-toast";

export function useLogin() {
    const navigate = useNavigate();
    const {isLoading: isLogging, mutate: login} = useMutation({
        mutationFn: ({email, password}) => loginApi({email, password}),
        onSuccess: () => {
            toast.success("Welcome Back!");
            navigate("/dashboard");
        },
        onError: (error) => {
            console.log(error.message);
            toast.error("something went wrong, pleast try to login again.")
        }
    });

    return {isLogging, login}
}

UPDATE:

  • printing the user object inside useEffect() is undefined but it's not inside userUser()

  • when I had removed this condition if(!isAuthenticated && !isLoading) navigate("/login"); I got redirected to the /dashboard but nothing appeared, the page was white, which is the same case of all other pages


Solution

  • I found the problem, my problem was in 2 things:

    • first: the async keyword in the useUser hook, it is removed now

    • second: I changed the routers' implementation to be like this:

      const router = createBrowserRouter([

      {
        element: <ProtectedRoutes><AppLayouts/></ProtectedRoutes>,
          children: [
            {
              path: "/",
              element: <Navigate to="/dashboard" replace />,
            },
            {
              path: "/dashboard",
              element: <Dashboard />,
            },
            {
              path: "/users",
              element: <NewUsers />,
            },
            {
              path: "/account",
              element: <Account />,
            },
            {
              path: "/bookings",
              element: <Bookings />,
            },
            {
              path: "/bookings/:id",
              element: <OneBookingDetails/>,
            },
            {
              path: "/checkin/:id",
              element: <Checkin/>,
            },
            {
              path: "/cabins",
              element: <Cabins />,
            },
            {
              path: "/settings",
              element: <Settings />,
            }
          ]
      }, 
      {
        path: "/login",
        element: <Login />,
      },
      {
        path: "*",
        element: <PageNotFound />,
      }]);
      

    now everything is working fine.