157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
"use client";
|
|
|
|
import { useState, useCallback } from "react";
|
|
import axios, {
|
|
AxiosRequestConfig,
|
|
AxiosError,
|
|
InternalAxiosRequestConfig,
|
|
} from "axios";
|
|
import toast from "react-hot-toast";
|
|
import { BASE_URL as base } from "@/components/main/BaseUrl";
|
|
import Cookies from "js-cookie";
|
|
import { clearAuthSession } from "@/lib/auth/session";
|
|
|
|
const BASE_URL = base;
|
|
const axiosInstance = axios.create({
|
|
baseURL: BASE_URL,
|
|
timeout: 900000, // 5 دقیقه (300,000 میلیثانیه)
|
|
maxContentLength: Infinity,
|
|
maxBodyLength: Infinity,
|
|
});
|
|
|
|
const getToken = (): string => {
|
|
if (typeof window !== "undefined") {
|
|
const token = Cookies.get("token");
|
|
return token ? `Bearer ${token}` : "";
|
|
}
|
|
return "";
|
|
};
|
|
|
|
// اضافه کردن توکن به هر درخواست
|
|
axiosInstance.interceptors.request.use(
|
|
(config: InternalAxiosRequestConfig) => {
|
|
if (config.headers) {
|
|
config.headers["Authorization"] = getToken();
|
|
}
|
|
return config;
|
|
},
|
|
(error) => Promise.reject(error)
|
|
);
|
|
|
|
// بررسی noToast در headers و جلوگیری از نمایش toast در پاسخها
|
|
axiosInstance.interceptors.response.use(
|
|
(response) => {
|
|
if (!response.config.headers?.["X-No-Toast"] && response.data?.message) {
|
|
// toast.success(response.data.message);
|
|
}
|
|
return response;
|
|
},
|
|
(error: AxiosError) => {
|
|
const { response, config } = error;
|
|
|
|
if (response) {
|
|
const { status, data } = response;
|
|
const noToast = config?.headers?.["X-No-Toast"];
|
|
|
|
if (status === 401 && !noToast) {
|
|
handleUnauthorized();
|
|
} else if (status === 422) {
|
|
const errors = (data as { [key: string]: string[] }).errors || {};
|
|
if (!noToast) {
|
|
if (
|
|
typeof data === "object" &&
|
|
(data as { message?: string }).message
|
|
) {
|
|
toast.error((data as { message: string }).message);
|
|
} else {
|
|
Object.values(errors).forEach((messages) => {
|
|
(messages as unknown as string[]).forEach((message) =>
|
|
toast.error(message)
|
|
);
|
|
});
|
|
}
|
|
}
|
|
} else if ([429, 500, 503].includes(status)) {
|
|
if (!noToast) {
|
|
// toast.error("An unexpected error occurred. Please try again later.");
|
|
}
|
|
} else {
|
|
if (!noToast) {
|
|
// toast.error((data as any)?.message || "An error occurred.");
|
|
}
|
|
}
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
const handleUnauthorized = (): void => {
|
|
if (typeof window === "undefined") return;
|
|
|
|
const path = window.location.pathname;
|
|
if (path.startsWith("/login") || path.startsWith("/register")) return;
|
|
|
|
clearAuthSession().finally(() => {
|
|
window.location.href = "/login";
|
|
});
|
|
};
|
|
|
|
// تایپ اصلاحشده برای درخواستها
|
|
interface RequestConfig extends AxiosRequestConfig {
|
|
noToast?: boolean;
|
|
}
|
|
|
|
const useAxios = () => {
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
const [error, setError] = useState<AxiosError | null>(null);
|
|
|
|
const request = useCallback(
|
|
async <T,>(
|
|
method: AxiosRequestConfig["method"],
|
|
url: string,
|
|
data: unknown = null,
|
|
config: RequestConfig = {}
|
|
): Promise<T> => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const isFormData = data instanceof FormData;
|
|
|
|
const response = await axiosInstance({
|
|
method,
|
|
url,
|
|
data,
|
|
...config,
|
|
headers: {
|
|
|
|
|
|
...config.headers,
|
|
...(isFormData ? {} : { "Content-Type": "application/json" }), // حذف Content-Type برای FormData
|
|
...(config.noToast ? { "X-No-Toast": "true" } : {}), // ارسال noToast به عنوان یک هدر
|
|
},
|
|
});
|
|
|
|
return response.data;
|
|
} catch (err) {
|
|
setError(err as AxiosError);
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
},
|
|
[]
|
|
);
|
|
|
|
return {
|
|
request,
|
|
loading,
|
|
error,
|
|
};
|
|
};
|
|
|
|
export default useAxios;
|