import React, { createContext, useContext, useState, useEffect } from 'react'; import axios from 'axios'; const AuthContext = createContext(); export const useAuth = () => useContext(AuthContext); export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const API_URL = import.meta.env.VITE_API_URL; // Keep HF Space alive — ping every 25 minutes to prevent sleeping useEffect(() => { const ping = () => axios.get(`${API_URL}/users`).catch(() => {}); ping(); // initial ping on load const interval = setInterval(ping, 25 * 60 * 1000); return () => clearInterval(interval); }, []); useEffect(() => { const initializeAuth = async () => { console.log('[Auth] Initializing authentication...'); const token = localStorage.getItem('token'); if (token) { console.log('[Auth] Found token in localStorage, setting Authorization header.'); axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; try { console.log('[Auth] Fetching user profile from:', `${API_URL}/users/me`); const response = await axios.get(`${API_URL}/users/me`); console.log('[Auth] Profile fetched successfully:', response.data); setUser(response.data); } catch (error) { console.error('[Auth] Failed to fetch profile:', error); // Only logout on explicit authorization failures (e.g. 401, 403). Keep session on server network errors. if (error.response && (error.response.status === 401 || error.response.status === 403 || error.response.status === 404)) { console.warn('[Auth] Token is expired, invalid, or user was not found on server. Logging out.'); logout(); } else { console.warn('[Auth] Server is unreachable or returned network error. Retaining session.'); const cachedUser = localStorage.getItem('user'); if (cachedUser) { try { const parsed = JSON.parse(cachedUser); console.log('[Auth] Loaded cached user from localStorage:', parsed); setUser(parsed); } catch (parseErr) { console.error('[Auth] Failed to parse cached user:', parseErr); logout(); } } } } } else { console.log('[Auth] No token found in localStorage.'); } setLoading(false); }; initializeAuth(); }, []); const login = async (email, password) => { try { const response = await axios.post(`${API_URL}/users/login`, { email, password }); handleAuthResponse(response.data); return { success: true }; } catch (error) { return { success: false, message: error.response?.data?.message || 'Login failed' }; } }; const register = async (email, password, displayName) => { try { const response = await axios.post(`${API_URL}/users/register`, { email, password, displayName }); handleAuthResponse(response.data); return { success: true }; } catch (error) { return { success: false, message: error.response?.data?.message || 'Registration failed' }; } }; const googleLogin = async (idToken) => { try { const response = await axios.post(`${API_URL}/users/google-login`, { idToken }); handleAuthResponse(response.data); return { success: true }; } catch (error) { return { success: false, message: error.response?.data?.message || 'Google Login failed' }; } }; const logout = () => { setUser(null); localStorage.removeItem('user'); localStorage.removeItem('token'); delete axios.defaults.headers.common['Authorization']; }; const updateUser = (updatedUser) => { setUser(updatedUser); localStorage.setItem('user', JSON.stringify(updatedUser)); }; const handleAuthResponse = (data) => { const { user, token } = data; setUser(user); localStorage.setItem('user', JSON.stringify(user)); localStorage.setItem('token', token); axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; }; return ( {!loading && children} ); };