Fix React error #130 - Remove authentication race condition
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -36,13 +36,19 @@ export const AdminAuthProvider: React.FC<AdminAuthProviderProps> = ({ 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<AdminAuthProviderProps> = ({ 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 = () => {
|
||||
|
||||
@@ -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<Record<string, string>>({});
|
||||
const [loginSuccess, setLoginSuccess] = useState(false);
|
||||
|
||||
// Redirect if already authenticated
|
||||
if (isAuthenticated) {
|
||||
// Redirect if already authenticated or login successful
|
||||
if (isAuthenticated || loginSuccess) {
|
||||
return <Navigate to="/admin/dashboard" replace />;
|
||||
}
|
||||
|
||||
@@ -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.');
|
||||
|
||||
@@ -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<FormData>({
|
||||
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<string, string> = {};
|
||||
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');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user