import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { getStoredUser, storeUser, clearStoredUser } from '../../shared/lib/auth'; import type { User } from '../../shared/types/auth'; // ───────────────────────────────────────────────────────────────────────────── // Types // ───────────────────────────────────────────────────────────────────────────── interface AuthContextValue { /** Currently authenticated user, or null when logged out */ user: User | null; /** True while the initial session hydration from localStorage is pending */ isLoading: boolean; /** Attempt login — returns true on success, false on invalid credentials */ login: (email: string, password: string) => boolean; /** Clear session and redirect to /login */ logout: () => void; } // ───────────────────────────────────────────────────────────────────────────── // Context // ───────────────────────────────────────────────────────────────────────────── const AuthContext = createContext(null); const AUTH_PATHS = ['/login', '/forgot-password', '/verify-email', '/reset-password']; // ───────────────────────────────────────────────────────────────────────────── // Provider // ───────────────────────────────────────────────────────────────────────────── /** * `AuthProvider` — manages authentication state for the app. * * Must be rendered **inside** `` so that `useNavigate` is available. * Wrap your `` tree with this provider to give all pages access to * `user`, `login`, and `logout` via `useAuth()` — no prop drilling needed. * * @example * ```tsx * * * * * * ``` */ export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); const navigate = useNavigate(); // Hydrate session from localStorage on mount useEffect(() => { try { setUser(getStoredUser()); } finally { setIsLoading(false); } }, []); // Redirect authenticated users away from auth-only pages useEffect(() => { if (!isLoading && user && AUTH_PATHS.includes(window.location.pathname)) { navigate('/home', { replace: true }); } }, [isLoading, user, navigate]); const login = useCallback( (email: string, password: string): boolean => { if (!email.trim() || !password.trim()) return false; const userData: User = { email }; storeUser(userData); setUser(userData); navigate('/home'); return true; }, [navigate] ); const logout = useCallback(() => { clearStoredUser(); setUser(null); navigate('/login'); }, [navigate]); return ( {children} ); } // ───────────────────────────────────────────────────────────────────────────── // Hook // ───────────────────────────────────────────────────────────────────────────── /** * `useAuth` — consume authentication state anywhere inside ``. * * @throws if called outside `` */ export function useAuth(): AuthContextValue { const ctx = useContext(AuthContext); if (!ctx) throw new Error('useAuth must be used within '); return ctx; }