Fix navigation issues with ProtectedRoute

Fixed infinite redirect loop and navigation blocking in ProtectedRoute component. The issue was that the useEffect was running on every render when navigating between admin routes.

## Changes:
- Added hasChecked state to ensure effect only runs once per mount
- Prevents multiple redirects and navigation blocking
- Allows smooth navigation between admin and member pages after login

## Technical Details:
- Before: useEffect ran on every render with requireAdmin in dependencies
- After: useEffect runs once when auth loading completes
- This prevents React Router navigation conflicts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-01-04 18:05:38 +07:00
parent e79e982401
commit e4a09a676e

View File

@@ -1,4 +1,4 @@
import { useEffect } from 'react'; import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
@@ -11,9 +11,13 @@ interface ProtectedRouteProps {
export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRouteProps) { export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRouteProps) {
const { user, loading: authLoading } = useAuth(); const { user, loading: authLoading } = useAuth();
const navigate = useNavigate(); const navigate = useNavigate();
const [hasChecked, setHasChecked] = useState(false);
useEffect(() => { useEffect(() => {
if (!authLoading) { // Only run effect once after auth loading completes
if (!authLoading && !hasChecked) {
setHasChecked(true);
if (!user) { if (!user) {
// Save current URL to redirect back after login // Save current URL to redirect back after login
const currentPath = window.location.pathname + window.location.search; const currentPath = window.location.pathname + window.location.search;
@@ -32,10 +36,10 @@ export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRout
} }
} }
} }
}, [user, authLoading, navigate, requireAdmin]); }, [user, authLoading, navigate, requireAdmin, hasChecked]);
// Show loading skeleton while checking auth // Show loading skeleton while checking auth
if (authLoading) { if (authLoading || !hasChecked) {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<div className="container mx-auto px-4 py-8"> <div className="container mx-auto px-4 py-8">