"use client"; import { createContext, useContext, useState, useEffect, useCallback } from "react"; const AuthContext = createContext(null); const TOKEN_KEY = "auth_token"; async function fetchCurrentUser(token) { const res = await fetch("/api/v1/auth/me", { headers: { Authorization: `Bearer ${token}` }, }); if (!res.ok) return null; return res.json(); } export function AuthProvider({ children }) { const [user, setUser] = useState(null); const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); const refreshUser = useCallback(async (providedToken) => { const activeToken = providedToken ?? token; if (!activeToken) { setUser(null); return null; } const userInfo = await fetchCurrentUser(activeToken); if (!userInfo) { localStorage.removeItem(TOKEN_KEY); setToken(null); setUser(null); return null; } if (!token) { setToken(activeToken); } setUser(userInfo); return userInfo; }, [token]); useEffect(() => { const stored = localStorage.getItem(TOKEN_KEY); if (!stored) { setLoading(false); return; } refreshUser(stored) .catch(() => { localStorage.removeItem(TOKEN_KEY); setToken(null); setUser(null); }) .finally(() => setLoading(false)); }, [refreshUser]); const login = useCallback(async (username, password) => { const res = await fetch("/api/v1/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password }), }); let data; try { data = await res.json(); } catch { throw new Error("Unable to log in, please try again later."); } if (!res.ok) { throw new Error(data.message || "Unable to log in, please try again later."); } const jwt = data.token; localStorage.setItem(TOKEN_KEY, jwt); setToken(jwt); const userInfo = await refreshUser(jwt); return userInfo; }, [refreshUser]); const register = useCallback(async ({ username, password, email, firstName, lastName, phone }) => { const res = await fetch("/api/v1/auth/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password, email, firstName, lastName, phone }), }); let data; try { data = await res.json(); } catch { throw new Error("Unable to register, please try again later."); } if (!res.ok) { if (data.errors && typeof data.errors === "object") { const fieldErrors = Object.entries(data.errors) .map(([field, msg]) => `${field}: ${msg}`) .join(", "); throw new Error(fieldErrors || data.message || "Unable to register, please try again later."); } throw new Error(data.message || "Unable to register, please try again later."); } const jwt = data.token; localStorage.setItem(TOKEN_KEY, jwt); setToken(jwt); const userInfo = await refreshUser(jwt); return userInfo; }, [refreshUser]); const logout = useCallback(() => { localStorage.removeItem(TOKEN_KEY); setToken(null); setUser(null);}, []); return ( {children} ); } export function useAuth() { const ctx = useContext(AuthContext); if (!ctx) { throw new Error("useAuth must be used within an AuthProvider"); } return ctx; }