/** * Auth Context * * Provides authentication state and methods to the application */ 'use client'; import React, { createContext, useContext, useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { login as apiLogin, register as apiRegister, logout as apiLogout, getCurrentUser, } from '../api/auth'; import { hasSession, clearAuthTokens } from '../api/client'; import type { UserPayload } from '@/types/api'; interface AuthContextType { user: UserPayload | null; loading: boolean; login: ( email: string, password: string, redirectTo?: string, rememberMe?: boolean ) => Promise; register: (data: { email: string; password: string; firstName: string; lastName: string; organizationId: string; }) => Promise; logout: () => Promise; refreshUser: () => Promise; isAuthenticated: boolean; } const AuthContext = createContext(undefined); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const router = useRouter(); // Helper function to check if user is authenticated (session flag cookie) const isAuthenticated = () => { return hasSession(); }; useEffect(() => { // Check if user is already logged in const checkAuth = async () => { try { if (isAuthenticated()) { // Try to fetch current user from API (will auto-refresh the session if expired) try { const currentUser = await getCurrentUser(); setUser(currentUser); } catch (apiError) { console.error('Failed to fetch user from API:', apiError); // If API fails after session refresh attempt, clear everything clearAuthTokens(); setUser(null); } } } catch (error) { console.error('Auth check failed, clearing session:', error); clearAuthTokens(); setUser(null); } finally { setLoading(false); } }; checkAuth(); // Check token validity every 5 minutes and refresh if needed const tokenCheckInterval = setInterval( async () => { if (isAuthenticated()) { try { // This will automatically refresh the token if it's expired (via API client) await getCurrentUser(); } catch (error) { console.error('Token validation failed:', error); // If token refresh fails, user will be redirected to login by the API client } } }, 5 * 60 * 1000 ); // 5 minutes return () => clearInterval(tokenCheckInterval); }, []); const login = async ( email: string, password: string, redirectTo = '/dashboard', rememberMe = false ) => { try { await apiLogin({ email, password, rememberMe }); // Fetch complete user profile after login (session lives in httpOnly cookies) const currentUser = await getCurrentUser(); setUser(currentUser); router.push(redirectTo); } catch (error) { throw error; } }; const register = async (data: { email: string; password: string; firstName: string; lastName: string; organizationId: string; }) => { try { await apiRegister(data); // Fetch complete user profile after registration const currentUser = await getCurrentUser(); setUser(currentUser); router.push('/dashboard'); } catch (error) { throw error; } }; const logout = async () => { try { await apiLogout(); } finally { setUser(null); router.push('/login'); } }; const refreshUser = async () => { try { const currentUser = await getCurrentUser(); setUser(currentUser); } catch (error) { console.error('Failed to refresh user:', error); } }; const value = { user, loading, login, register, logout, refreshUser, isAuthenticated: !!user, }; return {children}; } export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }