Files
modstagram-next/src/hooks/useAxios.tsx
2026-07-07 12:50:20 +03:30

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;