60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import axios from "axios";
|
|
import { useAuthStore } from "@/store/authStore";
|
|
import { useTenantStore } from "@/store/tenantStore";
|
|
import { useLocaleStore } from "@/store/uiStore";
|
|
import { useApiStore } from "@/store/uiStore";
|
|
|
|
export const apiClient = axios.create({
|
|
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:9191",
|
|
timeout: 25000
|
|
});
|
|
|
|
apiClient.interceptors.request.use((config) => {
|
|
const auth = useAuthStore.getState();
|
|
const tenantId = useTenantStore.getState().tenantId || auth.tenantId;
|
|
const locale = useLocaleStore.getState().locale;
|
|
|
|
if (auth.accessToken) {
|
|
config.headers.Authorization = `${auth.tokenType ?? "Bearer"} ${auth.accessToken}`;
|
|
}
|
|
if (tenantId) {
|
|
config.headers["X-Tenant-Id"] = tenantId;
|
|
}
|
|
if (locale) {
|
|
config.headers["Accept-Language"] = locale === "id" ? "id-ID" : "en-US";
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
apiClient.interceptors.response.use(
|
|
(response) => response,
|
|
(error) => {
|
|
const status = error?.response?.status;
|
|
const message = error?.response?.data?.message || error.message;
|
|
const ui = useApiStore.getState();
|
|
if (status === 401) {
|
|
ui.addToast(message || "Unauthorized", "error");
|
|
useAuthStore.getState().clearAuth();
|
|
if (typeof window !== "undefined") {
|
|
window.location.href = "/(auth)/login";
|
|
}
|
|
}
|
|
|
|
if (status === 403) {
|
|
ui.addToast(message || "Forbidden", "error");
|
|
}
|
|
|
|
return Promise.reject(new Error(message ?? "Request failed"));
|
|
}
|
|
);
|
|
|
|
export async function unwrap<T>(promise: ReturnType<typeof apiClient.request>): Promise<T> {
|
|
const response = await promise;
|
|
const payload = response.data;
|
|
if (payload && typeof payload.success === "boolean" && payload.success === false) {
|
|
throw new Error(payload.message ?? "Business error");
|
|
}
|
|
return payload.data as T;
|
|
}
|