diff --git a/src/App.tsx b/src/App.tsx index cfea967..da9cbfb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import { AuthProvider } from "@/hooks/useAuth"; import { CartProvider } from "@/contexts/CartContext"; import { BrandingProvider } from "@/hooks/useBranding"; +import { ProtectedRoute } from "@/components/ProtectedRoute"; import Index from "./pages/Index"; import Auth from "./pages/Auth"; import ConfirmOTP from "./pages/ConfirmOTP"; @@ -65,25 +66,131 @@ const App = () => ( } /> } /> } /> - + {/* Member routes */} - } /> - } /> - } /> - } /> - } /> - + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + {/* Admin routes */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + } /> diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx new file mode 100644 index 0000000..5cfbd29 --- /dev/null +++ b/src/components/ProtectedRoute.tsx @@ -0,0 +1,64 @@ +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useAuth } from '@/hooks/useAuth'; +import { Skeleton } from '@/components/ui/skeleton'; + +interface ProtectedRouteProps { + children: React.ReactNode; + requireAdmin?: boolean; +} + +export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRouteProps) { + const { user, loading: authLoading } = useAuth(); + const navigate = useNavigate(); + + useEffect(() => { + if (!authLoading) { + if (!user) { + // Save current URL to redirect back after login + const currentPath = window.location.pathname + window.location.search; + sessionStorage.setItem('redirectAfterLogin', currentPath); + navigate('/auth'); + return; + } + + // Check for admin role if required + if (requireAdmin) { + const userRole = user.user_metadata?.role; + if (userRole !== 'admin') { + // Redirect non-admin users to member dashboard + navigate('/dashboard'); + return; + } + } + } + }, [user, authLoading, navigate, requireAdmin]); + + // Show loading skeleton while checking auth + if (authLoading) { + return ( +
+
+
+ + + + +
+
+
+ ); + } + + // Don't render children if user is not authenticated + if (!user) { + return null; + } + + // Don't render if admin access required but user is not admin + if (requireAdmin && user.user_metadata?.role !== 'admin') { + return null; + } + + return <>{children}; +} diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index a4c975e..a23c459 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -29,7 +29,14 @@ export default function Auth() { useEffect(() => { if (user) { - navigate('/dashboard'); + // Check if there's a saved redirect path + const savedRedirect = sessionStorage.getItem('redirectAfterLogin'); + if (savedRedirect) { + sessionStorage.removeItem('redirectAfterLogin'); + navigate(savedRedirect); + } else { + navigate('/dashboard'); + } } }, [user, navigate]); @@ -101,8 +108,12 @@ export default function Auth() { toast({ title: 'Error', description: error.message, variant: 'destructive' }); setLoading(false); } else { - // Get redirect from URL state or use default - const redirectTo = (location.state as any)?.redirectTo || '/dashboard'; + // Get redirect from sessionStorage or use default + const savedRedirect = sessionStorage.getItem('redirectAfterLogin'); + const redirectTo = savedRedirect || '/dashboard'; + if (savedRedirect) { + sessionStorage.removeItem('redirectAfterLogin'); + } navigate(redirectTo); setLoading(false); }