From 2e10374e2c4134c6e5ae2afca21c77cd2c32c25a Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 7 Jul 2025 13:12:39 +0200 Subject: [PATCH] Fix React error #130 - Remove authentication race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove setTimeout delays in AdminAuthContext login function - Make authentication state updates synchronous - Replace setTimeout navigation with state-based navigation in AdminLoginPage - Add proper error handling and component lifecycle management in CreateEventPage - Prevent navigation if component unmounts during async operations This fixes the issue where users would see React error #130 during login and couldn't create events or save settings. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- frontend/src/contexts/AdminAuthContext.tsx | 23 +++++++++-------- frontend/src/pages/admin/AdminLoginPage.tsx | 17 +++++-------- frontend/src/pages/admin/CreateEventPage.tsx | 26 ++++++++++++++++---- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/frontend/src/contexts/AdminAuthContext.tsx b/frontend/src/contexts/AdminAuthContext.tsx index c00e6f8..4a9e074 100644 --- a/frontend/src/contexts/AdminAuthContext.tsx +++ b/frontend/src/contexts/AdminAuthContext.tsx @@ -36,13 +36,19 @@ export const AdminAuthProvider: React.FC = ({ children } useEffect(() => { // Check if user has a valid token on mount const checkAuth = async () => { - const token = getAuthToken(true); - if (token) { - // For now, just assume the token is valid - // TODO: Validate token with backend and get user info - setIsAuthenticated(true); + try { + const token = getAuthToken(true); + if (token) { + // For now, just assume the token is valid + // TODO: Validate token with backend and get user info + setIsAuthenticated(true); + } + } catch (error) { + console.error('Auth check error:', error); + setError('Failed to check authentication'); + } finally { + setIsLoading(false); } - setIsLoading(false); }; checkAuth(); @@ -52,10 +58,7 @@ export const AdminAuthProvider: React.FC = ({ children } // Token is already stored in cookie by authService setUser(user); setError(null); - // Small delay to ensure state is properly updated - setTimeout(() => { - setIsAuthenticated(true); - }, 100); + setIsAuthenticated(true); }; const logout = () => { diff --git a/frontend/src/pages/admin/AdminLoginPage.tsx b/frontend/src/pages/admin/AdminLoginPage.tsx index 86d103f..74e4a83 100644 --- a/frontend/src/pages/admin/AdminLoginPage.tsx +++ b/frontend/src/pages/admin/AdminLoginPage.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useNavigate, Navigate } from 'react-router-dom'; +import { Navigate } from 'react-router-dom'; import { Lock, Mail, Eye, EyeOff, AlertCircle } from 'lucide-react'; import { toast } from 'react-toastify'; @@ -9,7 +9,6 @@ import { authService } from '../../services/auth.service'; import { getAuthToken } from '../../config/api'; export const AdminLoginPage: React.FC = () => { - const navigate = useNavigate(); const { isAuthenticated, login } = useAdminAuth(); const [formData, setFormData] = useState({ @@ -19,9 +18,10 @@ export const AdminLoginPage: React.FC = () => { const [showPassword, setShowPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); const [errors, setErrors] = useState>({}); + const [loginSuccess, setLoginSuccess] = useState(false); - // Redirect if already authenticated - if (isAuthenticated) { + // Redirect if already authenticated or login successful + if (isAuthenticated || loginSuccess) { return ; } @@ -58,10 +58,7 @@ export const AdminLoginPage: React.FC = () => { const response = await authService.adminLogin(formData); login(response.token, response.user); toast.success('Login successful!'); - // Add a small delay to ensure auth state is updated - setTimeout(() => { - navigate('/admin/dashboard'); - }, 200); + setLoginSuccess(true); } catch (error: any) { console.error('Login error:', error); @@ -71,9 +68,7 @@ export const AdminLoginPage: React.FC = () => { const token = getAuthToken(true); if (token) { // Login was successful, just had a connection issue - setTimeout(() => { - navigate('/admin/dashboard'); - }, 200); + setLoginSuccess(true); return; } toast.error('Network error. Please check your connection and try again.'); diff --git a/frontend/src/pages/admin/CreateEventPage.tsx b/frontend/src/pages/admin/CreateEventPage.tsx index 3a6225d..30edc22 100644 --- a/frontend/src/pages/admin/CreateEventPage.tsx +++ b/frontend/src/pages/admin/CreateEventPage.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Calendar, @@ -45,6 +45,13 @@ const COLOR_THEMES = [ export const CreateEventPage: React.FC = () => { const navigate = useNavigate(); + const isMountedRef = useRef(true); + + useEffect(() => { + return () => { + isMountedRef.current = false; + }; + }, []); const [formData, setFormData] = useState({ event_type: 'wedding', @@ -65,18 +72,27 @@ export const CreateEventPage: React.FC = () => { const createMutation = useMutation({ mutationFn: eventsService.createEvent, onSuccess: (data) => { - toast.success('Event created successfully!'); - navigate(`/admin/events/${data.id}`); + if (isMountedRef.current) { + toast.success('Event created successfully!'); + navigate(`/admin/events/${data.id}`); + } }, onError: (error: any) => { - if (error.response?.data?.errors) { + if (!isMountedRef.current) return; + + if (error.code === 'ERR_NETWORK' || error.code === 'ERR_CONNECTION_RESET') { + toast.error('Network error. Please check your connection and try again.'); + } else if (error.response?.data?.errors) { const newErrors: Record = {}; error.response.data.errors.forEach((err: any) => { newErrors[err.path] = err.msg; }); setErrors(newErrors); + } else if (error.response?.status === 401) { + toast.error('Session expired. Please login again.'); + navigate('/admin/login'); } else { - toast.error('Failed to create event'); + toast.error(error.response?.data?.error || 'Failed to create event'); } }, });