import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; import { api } from '../services/api'; interface User { id: string; username: string; email: string; role: 'student' | 'instructor' | 'admin' | 'visitor'; targetCultures: string[]; nativeLanguage?: string; } interface AuthContextType { user: User | null; loading: boolean; login: (email: string, password: string) => Promise; register: (userData: RegisterData) => Promise; logout: () => void; updateProfile: (data: Partial) => Promise; } interface RegisterData { username: string; email: string; password: string; role?: 'student' | 'instructor' | 'admin'; targetCultures?: string[]; nativeLanguage?: string; } const AuthContext = createContext(undefined); export const useAuth = () => { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }; interface AuthProviderProps { children: ReactNode; } export const AuthProvider: React.FC = ({ children }) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Check for stored token on app load const token = localStorage.getItem('token'); if (token) { api.defaults.headers.common['Authorization'] = `Bearer ${token}`; fetchUser(); } else { // Auto-setup visitor authentication setupVisitorAuth(); } }, []); const setupVisitorAuth = async () => { try { const response = await api.post('/api/auth/login', { email: 'visitor@example.com' }); const { token, user } = response.data; localStorage.setItem('token', token); api.defaults.headers.common['Authorization'] = `Bearer ${token}`; setUser(user); } catch (error) { console.error('Failed to setup visitor auth:', error); // Set a fallback visitor token const fallbackToken = `visitor_${Date.now()}`; localStorage.setItem('token', fallbackToken); api.defaults.headers.common['Authorization'] = `Bearer ${fallbackToken}`; setUser({ id: 'visitor', username: 'Visitor', email: 'visitor@example.com', role: 'visitor', targetCultures: [] }); } finally { setLoading(false); } }; const fetchUser = async () => { try { const response = await api.get('/api/auth/profile'); setUser(response.data); } catch (error) { console.error('Failed to fetch user:', error); localStorage.removeItem('token'); delete api.defaults.headers.common['Authorization']; // Try to setup visitor auth as fallback setupVisitorAuth(); return; } finally { setLoading(false); } }; const login = async (email: string, password: string) => { try { const response = await api.post('/api/auth/login', { email }); const { token, user } = response.data; localStorage.setItem('token', token); localStorage.setItem('user', JSON.stringify(user)); api.defaults.headers.common['Authorization'] = `Bearer ${token}`; setUser(user); } catch (error: any) { console.error('Login error:', error); throw new Error(error.response?.data?.error || 'Login failed'); } }; const register = async (userData: RegisterData) => { try { const response = await api.post('/api/auth/register', userData); const { token, user } = response.data; localStorage.setItem('token', token); localStorage.setItem('user', JSON.stringify(user)); api.defaults.headers.common['Authorization'] = `Bearer ${token}`; setUser(user); } catch (error: any) { throw new Error(error.response?.data?.error || 'Registration failed'); } }; const logout = () => { localStorage.removeItem('token'); delete api.defaults.headers.common['Authorization']; setUser(null); // Setup visitor auth after logout setupVisitorAuth(); }; const updateProfile = async (data: Partial) => { try { const response = await api.put('/api/auth/profile', data); setUser(response.data); } catch (error: any) { throw new Error(error.response?.data?.error || 'Profile update failed'); } }; return ( {children} ); };