diff --git a/src/context/AuthContext.js b/src/context/AuthContext.js index ca70795..b029b7a 100644 --- a/src/context/AuthContext.js +++ b/src/context/AuthContext.js @@ -54,21 +54,75 @@ export const AuthProvider = ({ children }) => { }; const login = async (email, password) => { - const response = await axios.post(`${API_URL}/api/auth/login`, { email, password }); - const { access_token, user: userData } = response.data; - localStorage.setItem('token', access_token); - setToken(access_token); - setUser(userData); - - // Fetch user permissions (don't let this fail the login) try { - await fetchPermissions(access_token); - } catch (error) { - console.error('Failed to fetch permissions during login, will retry later:', error); - // Don't throw - permissions can be fetched later if needed - } + console.log('[AuthContext] Starting login request...'); - return userData; + const response = await axios.post( + `${API_URL}/api/auth/login`, + { email, password }, + { + timeout: 30000, // 30 second timeout + headers: { + 'Content-Type': 'application/json' + } + } + ); + + console.log('[AuthContext] Login response received:', { + status: response.status, + hasToken: !!response.data?.access_token, + hasUser: !!response.data?.user + }); + + const { access_token, user: userData } = response.data; + + // Store token first + localStorage.setItem('token', access_token); + console.log('[AuthContext] Token stored in localStorage'); + + // Update state + setToken(access_token); + setUser(userData); + console.log('[AuthContext] User state updated:', { + email: userData.email, + role: userData.role + }); + + // Fetch user permissions (don't let this fail the login) + // Use setTimeout to defer permission fetching slightly + setTimeout(async () => { + try { + console.log('[AuthContext] Fetching permissions...'); + await fetchPermissions(access_token); + console.log('[AuthContext] Permissions fetched successfully'); + } catch (error) { + console.error('[AuthContext] Failed to fetch permissions (non-critical):', { + message: error.message, + response: error.response?.data, + status: error.response?.status + }); + // Don't throw - permissions can be fetched later if needed + } + }, 100); // Small delay to ensure state is settled + + return userData; + } catch (error) { + // Enhanced error logging + console.error('[AuthContext] Login failed:', { + message: error.message, + response: error.response?.data, + status: error.response?.status, + code: error.code, + config: { + url: error.config?.url, + method: error.config?.method, + timeout: error.config?.timeout + } + }); + + // Re-throw to let Login component handle the error + throw error; + } }; const logout = () => { diff --git a/src/utils/api.js b/src/utils/api.js index 7a1a797..b79e35b 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -4,14 +4,60 @@ const API_URL = process.env.REACT_APP_BACKEND_URL; export const api = axios.create({ baseURL: `${API_URL}/api`, + timeout: 30000, // 30 second timeout for all requests }); -api.interceptors.request.use((config) => { - const token = localStorage.getItem('token'); - if (token) { - config.headers.Authorization = `Bearer ${token}`; +// Request interceptor - add auth token +api.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + (error) => { + console.error('[API] Request error:', error); + return Promise.reject(error); } - return config; -}); +); + +// Response interceptor - handle errors and retries +api.interceptors.response.use( + (response) => { + return response; + }, + async (error) => { + const config = error.config; + + // Don't retry if we've already retried or if it's a client error (4xx) + if (!config || config.__isRetry || (error.response && error.response.status < 500)) { + console.error('[API] Request failed:', { + url: config?.url, + method: config?.method, + status: error.response?.status, + message: error.message, + data: error.response?.data + }); + return Promise.reject(error); + } + + // Mark as retry to prevent infinite loops + config.__isRetry = true; + + // Retry after 1 second for server errors or network issues + console.warn('[API] Retrying request after 1s:', { + url: config.url, + method: config.method, + error: error.message + }); + + return new Promise((resolve) => { + setTimeout(() => { + resolve(api.request(config)); + }, 1000); + }); + } +); export default api;