125 lines
2.9 KiB
TypeScript
125 lines
2.9 KiB
TypeScript
"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<T> {
|
|
status: "Error" | "Success";
|
|
message: string;
|
|
data?: T;
|
|
}
|
|
|
|
async function request<T>(
|
|
url: string,
|
|
options: {
|
|
method?: "GET" | "POST" | "PATCH" | "DELETE";
|
|
body?: any;
|
|
requiresAuth?: boolean;
|
|
csrfToken?: boolean;
|
|
} = {},
|
|
): Promise<ApiResponse<T>> {
|
|
const { method = "GET", body, requiresAuth = true } = options;
|
|
const headers: Record<string, string> = {
|
|
"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}${url}`, {
|
|
method,
|
|
headers,
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
credentials: options.csrfToken ? "include" : "omit",
|
|
});
|
|
|
|
const apiResponse: ApiResponse<T> = await response.json();
|
|
|
|
if (apiResponse.status === "Error") {
|
|
throw new Error(apiResponse.message || "An unexpected error occurred");
|
|
}
|
|
|
|
return apiResponse;
|
|
}
|
|
|
|
async function fetcher<T>(
|
|
url: string,
|
|
requiresAuth: boolean = true,
|
|
csrfToken?: boolean,
|
|
): Promise<ApiResponse<T>> {
|
|
return request(url, { requiresAuth, csrfToken });
|
|
}
|
|
|
|
async function mutationHandler<T, A>(
|
|
url: string,
|
|
{
|
|
arg,
|
|
method,
|
|
requiresAuth,
|
|
csrfToken,
|
|
}: {
|
|
arg: A;
|
|
method: "GET" | "POST" | "PATCH" | "DELETE";
|
|
requiresAuth: boolean;
|
|
csrfToken?: boolean;
|
|
},
|
|
): Promise<ApiResponse<T>> {
|
|
return request(url, { method, body: arg, requiresAuth, csrfToken });
|
|
}
|
|
|
|
export function useApi<T>(
|
|
url: string,
|
|
config?: SWRConfiguration,
|
|
requiresAuth: boolean = true,
|
|
csrfToken?: boolean,
|
|
) {
|
|
const swr = useSWR<ApiResponse<T>>(
|
|
url,
|
|
() => fetcher(url, requiresAuth, csrfToken),
|
|
config,
|
|
);
|
|
|
|
return {
|
|
...swr,
|
|
data: swr.data?.data,
|
|
isLoading: swr.isLoading || swr.isValidating,
|
|
success: swr.data?.status === "Success",
|
|
};
|
|
}
|
|
|
|
export default function useApiMutation<T, A>(
|
|
endpoint: string,
|
|
config?: SWRMutationConfiguration<ApiResponse<T>, Error, string, A>,
|
|
method: "GET" | "POST" | "PATCH" | "DELETE" = "GET",
|
|
requiresAuth: boolean = false,
|
|
csrfToken?: boolean,
|
|
) {
|
|
const mutation = useSWRMutation<ApiResponse<T>, Error, string, A>(
|
|
endpoint,
|
|
(url, { arg }) =>
|
|
mutationHandler(url, { arg, method, requiresAuth, csrfToken }),
|
|
config,
|
|
);
|
|
return {
|
|
...mutation,
|
|
trigger: mutation.trigger as (
|
|
arg: A,
|
|
) => Promise<ApiResponse<T> | undefined>,
|
|
data: mutation.data?.data,
|
|
isSuccess: mutation.data?.status === "Success",
|
|
};
|
|
}
|