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
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.