| 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<void>; |
| register: (userData: RegisterData) => Promise<void>; |
| logout: () => void; |
| updateProfile: (data: Partial<User>) => Promise<void>; |
| } |
|
|
| interface RegisterData { |
| username: string; |
| email: string; |
| password: string; |
| role?: 'student' | 'instructor' | 'admin'; |
| targetCultures?: string[]; |
| nativeLanguage?: string; |
| } |
|
|
| const AuthContext = createContext<AuthContextType | undefined>(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<AuthProviderProps> = ({ children }) => { |
| const [user, setUser] = useState<User | null>(null); |
| const [loading, setLoading] = useState(true); |
|
|
| useEffect(() => { |
| |
| const token = localStorage.getItem('token'); |
| if (token) { |
| api.defaults.headers.common['Authorization'] = `Bearer ${token}`; |
| fetchUser(); |
| } else { |
| |
| 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); |
| |
| 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']; |
| |
| 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); |
| |
| setupVisitorAuth(); |
| }; |
|
|
| const updateProfile = async (data: Partial<User>) => { |
| 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 ( |
| <AuthContext.Provider value={{ |
| user, |
| loading, |
| login, |
| register, |
| logout, |
| updateProfile |
| }}> |
| {children} |
| </AuthContext.Provider> |
| ); |
| }; |