"use client"; import { useAuth } from "@/context/AuthContext"; import { useCallback, useMemo } from "react"; const DEFAULT_API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL ?? ""; export function useApi(baseUrl: string = DEFAULT_API_BASE) { const { token } = useAuth(); const apiFetch = useCallback( async (path: string, options: RequestInit = {}): Promise => { // Allow either full URLs or just `/api/...` const url = path.startsWith("http") ? path : `${baseUrl.replace(/\/$/, "")}${path}`; const headers: HeadersInit = { "Content-Type": "application/json", ...(options.headers || {}), ...(token ? { Authorization: `Bearer ${token}` } : {}), }; const res = await fetch(url, { ...options, headers, }); if (!res.ok) { let bodyText = ""; try { bodyText = await res.text(); } catch { // ignore } throw new Error( `API error ${res.status}: ${ bodyText || res.statusText || "Unknown error" }` ); } // handle 204 / empty body safely try { return (await res.json()) as T; } catch { return {} as T; } }, [baseUrl, token] // 👈 only changes when baseUrl or token change ); const get = useCallback( (path: string) => apiFetch(path, { method: "GET" }), [apiFetch] ); const post = useCallback( (path: string, body?: unknown) => apiFetch(path, { method: "POST", body: body !== undefined ? JSON.stringify(body) : undefined, }), [apiFetch] ); const put = useCallback( (path: string, body?: unknown) => apiFetch(path, { method: "PUT", body: body !== undefined ? JSON.stringify(body) : undefined, }), [apiFetch] ); const del = useCallback( (path: string) => apiFetch(path, { method: "DELETE" }), [apiFetch] ); // Optional: memoize the returned object so destructuring doesn't change refs return useMemo( () => ({ apiFetch, get, post, put, del }), [apiFetch, get, post, put, del] ); }