From 63fd48a4a986bedcb7f7fa41834e435dda0bb063 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 18:30:26 +0000 Subject: [PATCH] Fix: History replaceState overuse The commit addresses a "SecurityError: Attempt to use history.replaceState() more than 100 times per 10 seconds" error, likely caused by excessive calls to `history.replaceState()`. --- src/App.tsx | 44 +++++++++++++++++++---- src/components/auth/ProtectedRoute.tsx | 48 ++++++++++++-------------- src/stores/authStore.ts | 11 +++++- 3 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 96d55c2..92b44b2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,5 @@ - import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; -import { Suspense, lazy } from 'react'; +import { Suspense, lazy, useEffect } from 'react'; import { Toaster } from "@/components/ui/sonner"; import Auth from './pages/Auth'; import ProtectedRoute from './components/auth/ProtectedRoute'; @@ -19,22 +18,55 @@ const CartoesCredito = lazy(() => import('./pages/CartoesCredito')); function App() { const isLoggedIn = authStore((state) => state.isLoggedIn); + const setLoggedIn = authStore((state) => state.setLoggedIn); + + // Initialize authStore state once at mount time + useEffect(() => { + const storedAuth = localStorage.getItem('autenticado') === 'true'; + setLoggedIn(storedAuth); + }, [setLoggedIn]); return ( - : } /> - Carregando...}>} /> - Carregando...}>} /> + {/* The auth route should not be inside ProtectedRoute */} + : } + /> + + {/* Protected routes */} + + Carregando...}> + + + + } /> + + + Carregando...}> + + + + } /> + Carregando...}>} /> Carregando...}>} /> Carregando...}>} /> Carregando...}>} /> Carregando...}>} /> Carregando...}>} /> - Carregando...}>} /> + + {/* Not found route */} + Carregando...}> + + + } /> ); diff --git a/src/components/auth/ProtectedRoute.tsx b/src/components/auth/ProtectedRoute.tsx index ba70135..d27815c 100644 --- a/src/components/auth/ProtectedRoute.tsx +++ b/src/components/auth/ProtectedRoute.tsx @@ -3,61 +3,57 @@ import { ReactNode, useEffect, useState } from 'react'; import { Navigate, useLocation } from 'react-router-dom'; import { useToast } from "@/components/ui/use-toast"; import LoadingState from '../whatsapp/LoadingState'; +import { authStore } from '@/stores/authStore'; interface ProtectedRouteProps { children: ReactNode; } const ProtectedRoute = ({ children }: ProtectedRouteProps) => { - const [isAuthenticated, setIsAuthenticated] = useState(null); const [isLoading, setIsLoading] = useState(true); - const [shouldShowToast, setShouldShowToast] = useState(false); const { toast } = useToast(); const location = useLocation(); + const setLoggedIn = authStore((state) => state.setLoggedIn); + + // Use a single state variable to track authentication status + const [authStatus, setAuthStatus] = useState<'loading' | 'authenticated' | 'unauthenticated'>('loading'); useEffect(() => { - // Check authentication status only once on mount - const checkAuthentication = async () => { + const checkAuthentication = () => { try { - setIsLoading(true); - // Check if we have stored authentication status const storedAuth = localStorage.getItem('autenticado') === 'true'; const userId = localStorage.getItem('userId'); if (storedAuth && userId) { console.log('Usando autenticação armazenada: autenticado'); - setIsAuthenticated(true); + setAuthStatus('authenticated'); + setLoggedIn(true); } else { console.log('Nenhuma sessão encontrada, redirecionando para login'); - setIsAuthenticated(false); - setShouldShowToast(true); // Mark that we should show toast, but don't do it here + setAuthStatus('unauthenticated'); + setLoggedIn(false); + + // Only show toast once when transitioning to unauthenticated + toast({ + title: "Autenticação necessária", + description: "Por favor, faça login para acessar esta página" + }); } } catch (error) { console.error('Erro ao verificar autenticação:', error); - setIsAuthenticated(false); - setShouldShowToast(true); + setAuthStatus('unauthenticated'); + setLoggedIn(false); } finally { setIsLoading(false); } }; checkAuthentication(); - }, []); // Execute only on mount - - // Show toast in a separate useEffect to avoid re-render loops - useEffect(() => { - if (shouldShowToast) { - toast({ - title: "Autenticação necessária", - description: "Por favor, faça login para acessar esta página" - }); - setShouldShowToast(false); // Reset the flag after showing toast - } - }, [shouldShowToast, toast]); + }, [toast, setLoggedIn]); // Only check once on mount, with stable dependencies // Se estiver carregando, mostrar estado de carregamento - if (isLoading) { + if (isLoading || authStatus === 'loading') { return (
@@ -65,8 +61,8 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => { ); } - // Se não estiver autenticado, redirecionar para a página de login - if (!isAuthenticated) { + // Se não estiver autenticado, redirecionar para a página de login - use replace para evitar histórico + if (authStatus === 'unauthenticated') { return ; } diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts index 24d7435..c7c606d 100644 --- a/src/stores/authStore.ts +++ b/src/stores/authStore.ts @@ -6,7 +6,16 @@ interface AuthState { setLoggedIn: (status: boolean) => void; } +// Initialize with the persisted value from localStorage +const getInitialState = (): boolean => { + try { + return localStorage.getItem('autenticado') === 'true'; + } catch (e) { + return false; + } +}; + export const authStore = create((set) => ({ - isLoggedIn: localStorage.getItem('autenticado') === 'true', + isLoggedIn: getInitialState(), setLoggedIn: (status) => set({ isLoggedIn: status }), }));