import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from "axios"; import { toast } from "react-hot-toast"; // Use relative URL if NEXT_PUBLIC_API_URL is empty (same domain deployment) // Otherwise use the provided URL or default to localhost const API_URL = process.env.NEXT_PUBLIC_API_URL === "" ? "" // Empty string means use relative URLs (same domain) : (process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"); // Create axios instance const apiClient: AxiosInstance = axios.create({ baseURL: API_URL, timeout: 300000, // 5 minutes for long-running operations headers: { "Content-Type": "application/json", }, }); // Request interceptor apiClient.interceptors.request.use( (config: InternalAxiosRequestConfig) => { // Add auth token if available if (typeof window !== "undefined") { const authStorage = localStorage.getItem("auth-storage"); if (authStorage) { try { const auth = JSON.parse(authStorage); if (auth.state?.token) { config.headers.Authorization = `Bearer ${auth.state.token}`; } } catch (e) { // Ignore parsing errors } } } return config; }, (error) => { return Promise.reject(error); } ); // Response interceptor for error handling apiClient.interceptors.response.use( (response) => response, (error: AxiosError) => { if (error.response) { // Server responded with error status const status = error.response.status; const message = (error.response.data as any)?.detail || error.message || "An error occurred"; // Handle 401 Unauthorized - redirect to login if (status === 401) { if (typeof window !== "undefined" && !window.location.pathname.includes("/login")) { // Clear auth storage localStorage.removeItem("auth-storage"); // Redirect to login window.location.href = "/login"; } } // Don't show toast for 404s (handled in components) or 401s (handled above) if (status !== 404 && status !== 401) { toast.error(message); } } else if (error.request) { // Request made but no response toast.error("Network error. Please check your connection."); } else { // Something else happened toast.error("An unexpected error occurred"); } return Promise.reject(error); } ); export default apiClient;