import axios from "axios"; import Cookies from "js-cookie"; import { toast } from "react-toastify"; import { getAccessToken, setAccessToken, clearAccessToken } from "@/lib/tokenStore"; function extractErrorMessage(error) { const errors = error?.response?.data?.errors; if (Array.isArray(errors) && errors.length > 0 && errors[0]?.message) { return errors[0].message; } if (error?.response?.data?.message) { return error.response.data.message; } return "خطایی رخ داد. لطفاً دوباره تلاش کنید."; } const BASE_URL = process.env.NEXT_PUBLIC_API_URL; const api = axios.create({ baseURL: BASE_URL, headers: { "Content-Type": "application/json", }, }); let refreshPromise = null; async function refreshAccessToken() { if (!refreshPromise) { refreshPromise = fetch("/api/auth/refresh", { method: "POST" }) .then((res) => (res.ok ? res.json() : null)) .then((data) => { const token = data?.access_token ?? null; setAccessToken(token); return token; }) .catch(() => null) .finally(() => { refreshPromise = null; }); } return refreshPromise; } function handleSessionExpired() { clearAccessToken(); const hostname = window.location.hostname; const domain = hostname.includes("localhost") ? undefined : `.${hostname.split(".").slice(-2).join(".")}`; const opts = { path: "/", ...(domain && { domain }) }; ["uuid", "userInfo"].forEach((key) => Cookies.remove(key, opts)); window.location.href = "/login"; } api.interceptors.request.use( (config) => { if (config.requireAuth) { const token = getAccessToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } } return config; }, (error) => Promise.reject(error) ); api.interceptors.response.use( (response) => response.data, async (error) => { const original = error?.config; if ( error?.response?.status === 401 && original?.requireAuth && !original._retried && typeof window !== "undefined" ) { original._retried = true; const token = await refreshAccessToken(); if (token) { original.headers = { ...original.headers, Authorization: `Bearer ${token}` }; return api(original); } handleSessionExpired(); return Promise.reject(error); } if (typeof window !== "undefined" && !error?.config?.skipErrorToast) { toast.error(extractErrorMessage(error)); } return Promise.reject(error); } ); export default api;