"use client"; import { useRouter } from "next/navigation"; import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react"; import { User } from "@/lib/api"; type AuthContextValue = { token: string | null; setToken: (value: string | null) => void; setUser: (value: User | null) => void; logout: () => void; user: User | null; refreshUser: () => Promise; }; const AuthContext = createContext(null); export function AuthProvider({ children }: { children: React.ReactNode }) { const router = useRouter(); const [token, setTokenState] = useState(null); const [user, setUser] = useState(null); const tokenRef = useRef(null); const userRef = useRef(null); useEffect(() => { tokenRef.current = token; }, [token]); useEffect(() => { userRef.current = user; }, [user]); useEffect(() => { void fetch("/api/me", { credentials: "include", cache: "no-store" }) .then(async (response) => { if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return (await response.json()) as User; }) .then((current) => { setUser(current); setTokenState("authenticated"); }) .catch(() => { if (!tokenRef.current && !userRef.current) { setUser(null); setTokenState(null); } }); }, []); const value = useMemo(() => { const setToken = (next: string | null) => { setTokenState(next); }; return { token, setToken, setUser, logout: () => { setToken(null); void fetch("/api/logout", { method: "POST", credentials: "include" }); router.push("/login"); }, user, refreshUser: async () => { try { const response = await fetch("/api/me", { credentials: "include", cache: "no-store" }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const current = (await response.json()) as User; setUser(current); setTokenState("authenticated"); return current; } catch { if (!userRef.current) { setUser(null); setTokenState(null); } return null; } } }; }, [router, token, user]); return {children}; } export function useAuth() { const value = useContext(AuthContext); if (!value) { throw new Error("useAuth must be used inside AuthProvider"); } return value; }