'use client'; import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; import { useRouter } from 'next/navigation'; import apiClient from '@/lib/api/client'; export interface User { id: string; email: string; name: string; role: string; } export interface LoginCredentials { email: string; password: string; deviceFingerprint?: string; } export interface RegisterData { email: string; password: string; name: string; role?: string; } interface AuthContextType { user: User | null; isLoading: boolean; isAuthenticated: boolean; login: (credentials: LoginCredentials) => Promise; register: (data: RegisterData) => Promise; logout: () => Promise; refreshUser: () => Promise; } const AuthContext = createContext(undefined); export const AuthProvider = ({ children }: { children: ReactNode }) => { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); const router = useRouter(); const isAuthenticated = !!user; // Check authentication status on mount useEffect(() => { checkAuth(); }, []); const checkAuth = async () => { const token = localStorage.getItem('accessToken'); if (!token) { setIsLoading(false); return; } try { const response = await apiClient.get('/api/v1/auth/me'); setUser(response.data.data); } catch (error) { console.error('Auth check failed:', error); localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); } finally { setIsLoading(false); } }; const login = async (credentials: LoginCredentials) => { try { const deviceInfo = { deviceId: generateDeviceFingerprint(), platform: 'web', model: navigator.userAgent, osVersion: navigator.platform, }; const response = await apiClient.post('/api/v1/auth/login', { email: credentials.email, password: credentials.password, deviceInfo, }); // Backend returns { success, data: { user, tokens } } const { data: responseData } = response.data; const { tokens, user: userData } = responseData; localStorage.setItem('accessToken', tokens.accessToken); localStorage.setItem('refreshToken', tokens.refreshToken); setUser(userData); router.push('/'); } catch (error: any) { console.error('Login failed:', error); throw new Error(error.response?.data?.message || 'Login failed'); } }; const register = async (data: RegisterData) => { try { const deviceInfo = { deviceId: generateDeviceFingerprint(), platform: 'web', model: navigator.userAgent, osVersion: navigator.platform, }; const response = await apiClient.post('/api/v1/auth/register', { email: data.email, password: data.password, name: data.name, deviceInfo, }); // Backend returns { success, data: { user, family, tokens } } const { data: responseData } = response.data; const { tokens, user: userData } = responseData; if (!tokens?.accessToken || !tokens?.refreshToken) { throw new Error('Invalid response from server'); } const { accessToken, refreshToken } = tokens; localStorage.setItem('accessToken', accessToken); localStorage.setItem('refreshToken', refreshToken); setUser(userData); // Redirect to onboarding router.push('/onboarding'); } catch (error: any) { console.error('Registration failed:', error); throw new Error(error.response?.data?.message || error.message || 'Registration failed'); } }; const logout = async () => { try { await apiClient.post('/api/v1/auth/logout'); } catch (error) { console.error('Logout failed:', error); } finally { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); setUser(null); router.push('/login'); } }; const refreshUser = async () => { try { const response = await apiClient.get('/api/v1/auth/me'); setUser(response.data.data); } catch (error) { console.error('Failed to refresh user:', error); } }; return ( {children} ); }; export const useAuth = () => { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }; // Helper function to generate a simple device fingerprint function generateDeviceFingerprint(): string { const navigator = window.navigator; const screen = window.screen; const data = [ navigator.userAgent, navigator.language, screen.colorDepth, screen.width, screen.height, new Date().getTimezoneOffset(), ].join('|'); // Simple hash function let hash = 0; for (let i = 0; i < data.length; i++) { const char = data.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; } return hash.toString(36); }