"use client"; import { API_URL } from "@/lib/constants"; import { getCookie } from "cookies-next"; import useSWR, { SWRConfiguration } from "swr"; import useSWRMutation, { type SWRMutationConfiguration } from "swr/mutation"; export interface ApiResponse { status: "Error" | "Success"; message: string; data?: T; } export async function request( endpoint: string, options: { method?: "GET" | "POST" | "PATCH" | "DELETE"; body?: any; requiresAuth?: boolean; csrfToken?: boolean; } = {}, ): Promise> { const { method = "GET", body, requiresAuth = true } = options; const headers: Record = { "Content-Type": "application/json", }; if (options.csrfToken) { const res: ApiResponse<{ csrf: string }> = await ( await fetch(`${API_URL}/csrf-token`) ).json(); if (res.data) headers["X-CSRF-Token"] = res.data.csrf; } if (requiresAuth) { const authToken = getCookie("auth_token"); if (!authToken) { throw new Error("User is not authenticated"); } headers.Authorization = `Bearer ${authToken}`; } const response = await fetch(`${API_URL}${endpoint}`, { method, headers, body: body ? JSON.stringify(body) : undefined, credentials: options.csrfToken ? "include" : "omit", }); const apiResponse: ApiResponse = await response.json(); if (apiResponse.status === "Error") { throw new Error(apiResponse.message || "An unexpected error occurred"); } return apiResponse; } async function fetcher( url: string, requiresAuth: boolean = true, csrfToken?: boolean, ): Promise> { return request(url, { requiresAuth, csrfToken }); } async function mutationHandler( url: string, { arg, method, requiresAuth, csrfToken, }: { arg: A; method: "GET" | "POST" | "PATCH" | "DELETE"; requiresAuth: boolean; csrfToken?: boolean; }, ): Promise> { return request(url, { method, body: arg, requiresAuth, csrfToken }); } export function useApi( endpoint: string, config?: SWRConfiguration, requiresAuth: boolean = true, csrfToken?: boolean, ) { const swr = useSWR>( endpoint, () => fetcher(endpoint, requiresAuth, csrfToken), config, ); return { ...swr, data: swr.data?.data, isLoading: swr.isLoading || swr.isValidating, success: swr.data?.status === "Success", }; } export default function useApiMutation( endpoint: string, config?: SWRMutationConfiguration, Error, string, A>, method: "GET" | "POST" | "PATCH" | "DELETE" = "GET", requiresAuth: boolean = false, csrfToken?: boolean, ) { const mutation = useSWRMutation, Error, string, A>( endpoint, (url, { arg }) => mutationHandler(url, { arg, method, requiresAuth, csrfToken }), config, ); return { ...mutation, trigger: mutation.trigger as ( arg: A, ) => Promise | undefined>, data: mutation.data?.data, isSuccess: mutation.data?.status === "Success", }; }