import axios from "axios"; import { useNavigate } from "react-router-dom"; import axiosRetry from "axios-retry"; import showToast from "../services/toastService"; import { startSignalR, stopSignalR } from "../services/signalRService"; const base_Url = process.env.VITE_BASE_URL; // const base_Url = "https://api.marcoaiot.com"; export const axiosClient = axios.create({ baseURL: base_Url, // Your Web API URL withCredentials: false, // Required if the API uses cookies headers: { "Content-Type": "application/json", // Specify the content type }, }); axiosRetry(axiosClient, { retries: 3 }); // Request interceptor to add Bearer token axiosClient.interceptors.request.use( async (config) => { if (config.authRequired) { const token = localStorage.getItem("jwtToken"); if (token) { config.headers["Authorization"] = `Bearer ${token}`; config._retry = true; } else { config._retry = false; } } return config; }, (error) => Promise.reject(error) ); // // Response interceptor to handle responses globally (optional) // Add an interceptor to handle expired tokens axiosClient.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; // Prevent infinite loop if (!originalRequest || originalRequest._retry) { return Promise.reject(error); } // Only show one toast per request if (!originalRequest._toastShown) { originalRequest._toastShown = true; if (error.code === "ERR_CONNECTION_REFUSED") { showToast("Unable to connect to the server. Please try again later.", "error"); } else if (error.code === "ERR_NETWORK") { showToast("Network error. Please check your connection.", "error"); redirectToLogin(); } else if (error.code === "ECONNABORTED") { showToast("Request timed out. Please try again.", "error"); } else if (error.response) { const status = error.response.status; const isRefreshRequest = error.config.url.includes("refresh-token"); if (status === 401 && !isRefreshRequest) { // Mark as retried to avoid loops originalRequest._retry = true; const refreshToken = localStorage.getItem("refreshToken"); if (!refreshToken || error.response.data?.errors === "Invalid or expired refresh token.") { redirectToLogin(); return Promise.reject(error); } stopSignalR(); try { // Refresh token const res = await axiosClient.post("/api/Auth/refresh-token", { token: localStorage.getItem("jwtToken"), refreshToken, }); const { token, refreshToken: newRefreshToken } = res.data.data; // Save new tokens localStorage.setItem("jwtToken", token); localStorage.setItem("refreshToken", newRefreshToken); startSignalR() // Set Authorization header originalRequest.headers["Authorization"] = `Bearer ${token}`; // Optional: Instead of retrying, you may choose to reload app or go to home return axiosClient(originalRequest); // <== only retry once } catch (refreshError) { redirectToLogin(); return Promise.reject(refreshError); } } } else { showToast("An unknown error occurred.", "error"); } } return Promise.reject(error); } ); // Generic API Call const apiRequest = async (method, url, data = {}, config = {}) => { try { const response = await axiosClient({ method, url, data: method !== "get" ? data : undefined, params: method === "get" ? data : undefined, ...config, }); return response.data; } catch (error) { throw error; } }; export const api = { // For public routes like login, set authRequired: false postPublic: (url, data = {}, customHeaders = {}) => apiRequest("post", url, data, { headers: { ...customHeaders }, authRequired: false, }), // For protected routes, authRequired defaults to true get: (url, params = {}, customHeaders = {}) => apiRequest("get", url, params, { headers: { ...customHeaders }, authRequired: true, }), post: (url, data = {}, customHeaders = {}) => apiRequest("post", url, data, { headers: { ...customHeaders }, authRequired: true, }), put: (url, data = {}, customHeaders = {}) => apiRequest("put", url, data, { headers: { ...customHeaders }, authRequired: true, }), delete: (url, data = {}, customHeaders = {}) => apiRequest("delete", url, data, { headers: { ...customHeaders }, authRequired: true, }), }; //export default axiosClient; function redirectToLogin() { window.location.href = "/auth/login"; }