"use client"; import React, { createContext, useContext, useEffect, useState, useCallback } from "react"; import { api } from "./api"; interface User { id: string; username: string; email: string; is_admin: boolean; created_at: string; } interface AuthContextType { user: User | null; token: string | null; loading: boolean; login: (email: string, password: string) => Promise; register: (username: string, email: string, password: string) => Promise; logout: () => void; } const AuthContext = createContext(undefined); export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); // Lazy initializer reads localStorage once — avoids setState-in-effect lint error const [token, setToken] = useState( () => (typeof window !== "undefined" ? localStorage.getItem("token") : null) ); // loading=true only when a token exists and needs server validation. // If there's no token we're already done — no effect setState needed. const [loading, setLoading] = useState( () => typeof window !== "undefined" && !!localStorage.getItem("token") ); // ── Validate saved token on mount ───────────────── // NOTE: no synchronous setState here — setLoading/setUser/setToken are // only called inside async callbacks (.then / .catch / .finally). useEffect(() => { if (!token) return; // loading is already false when token is null api .get("/api/v1/auth/me", { token }) .then(setUser) .catch(() => { localStorage.removeItem("token"); setToken(null); }) .finally(() => setLoading(false)); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // intentionally runs once on mount only const login = useCallback(async (email: string, password: string) => { const data = await api.post<{ access_token: string; user: User }>( "/api/v1/auth/login", { email, password } ); localStorage.setItem("token", data.access_token); setToken(data.access_token); setUser(data.user); }, []); const register = useCallback(async (username: string, email: string, password: string) => { const data = await api.post<{ access_token: string; user: User }>( "/api/v1/auth/register", { username, email, password } ); localStorage.setItem("token", data.access_token); setToken(data.access_token); setUser(data.user); }, []); const logout = useCallback(() => { localStorage.removeItem("token"); setToken(null); setUser(null); }, []); return ( {children} ); } export function useAuth() { const ctx = useContext(AuthContext); if (!ctx) throw new Error("useAuth must be used within AuthProvider"); return ctx; }