import axios, { type AxiosError, type AxiosResponse } from "axios"; import { store } from "@/main.ts"; import { addNewMessage, color } from "@/services/popupDisplayer.ts"; import Project from "./ApiClasses/Project"; import SectionCell from "./ApiClasses/SectionCell"; import Report from "./ApiClasses/Repport"; import Appointment from "./ApiClasses/Appointment"; const axiosInstance = axios.create({ baseURL: import.meta.env.VITE_BACKEND_URL, headers: { "Content-Type": "application/json", }, }); axiosInstance.interceptors.response.use( (response) => response, // Directly return successful responses. async (error) => { const originalRequest = error.config; if ( ((error.response && error.response.status === 401) || error.code == "ERR_NETWORK") && !originalRequest._retry && store.authenticated ) { originalRequest._retry = true; // Mark the request as retried to avoid infinite loops. try { await store.refreshUserToken(); // Update the authorization header with the new access token. axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${store.user.token}`; return axiosInstance(originalRequest); // Retry the original request with the new access token. } catch (refreshError) { // Handle refresh token errors by clearing stored tokens and redirecting to the login page. console.error("Token refresh failed:", refreshError); localStorage.removeItem("accessToken"); localStorage.removeItem("refreshToken"); window.location.href = "/login"; return Promise.reject(refreshError); } } return Promise.reject(error); // For all other errors, return the error as is. } ); // TODO: spawn a error modal function defaultApiErrorHandler(err: AxiosError) { addNewMessage(err.message, color.Red); } function defaultApiSuccessHandler(response: AxiosResponse) { addNewMessage(response.data, color.Green); } // Existing functions (maintained for backward compatibility) function callApi( endpoint: string, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(endpoint) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function postApi( endpoint: string, data: unknown, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post(endpoint, data) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function deleteApi( endpoint: string, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .delete(endpoint) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } // New functions based on Swagger documentation // Unauth API function finalizeAccount( onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post("/unauth/finalize") .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } // function requestJoinProject( // Not yet implemented [cite: 4] // projectId: number, // onSuccessHandler?: (response: AxiosResponse) => void, // onErrorHandler?: (error: AxiosError) => void // ): void { // axiosInstance // .post(`/unauth/request-join/${projectId}`) // .then((response) => { // if (onSuccessHandler) { // onSuccessHandler(response); // } else { // defaultApiSuccessHandler(response); // } // }) // .catch((error: AxiosError) => { // if (onErrorHandler) { // onErrorHandler(error); // } else { // defaultApiErrorHandler(error); // } // }); // } // Admin API function getPendingAccounts( onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get("/admin/pending-accounts") .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function validateUserAccount( userId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post(`/admin/accounts/validate/${userId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } // function getPendingProjectJoinRequests( // Not yet implemented [cite: 3] // onSuccessHandler?: (response: AxiosResponse) => void, // onErrorHandler?: (error: AxiosError) => void // ): void { // axiosInstance // .get("/admin/request-join") // .then((response) => { // if (onSuccessHandler) { // onSuccessHandler(response); // } else { // defaultApiSuccessHandler(response); // } // }) // .catch((error: AxiosError) => { // if (onErrorHandler) { // onErrorHandler(error); // } else { // defaultApiErrorHandler(error); // } // }); // } // function decideProjectJoinRequest( // Not yet implemented [cite: 3] // joinRequestId: number, // decision: { isAccepted: boolean }, // onSuccessHandler?: (response: AxiosResponse) => void, // onErrorHandler?: (error: AxiosError) => void // ): void { // axiosInstance // .post(`/admin/request-join/decision/${joinRequestId}`, decision) // .then((response) => { // if (onSuccessHandler) { // onSuccessHandler(response); // } else { // defaultApiSuccessHandler(response); // } // }) // .catch((error: AxiosError) => { // if (onErrorHandler) { // onErrorHandler(error); // } else { // defaultApiErrorHandler(error); // } // }); // } function getAdminProjects( onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get("/admin/projects") .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function addProjectManually( projectDetails: Project, // Replace 'any' with a proper type for project details if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post("/admin/projects", projectDetails) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getPendingProjects( onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get("/admin/projects/pending") .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function decidePendingProject( pendingProjectId: number, decision: { projectId: number; adminId: number; isAccepted: boolean }, // Replace 'any' with a proper type for project decision if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post(`/admin/projects/pending/decision/${pendingProjectId}`, decision) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function createAppointmentReport( appointmentId: number, reportContent: Report, // Replace 'any' with a proper type for report content if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post(`/admin/appointments/report/${appointmentId}`, reportContent) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function updateAppointmentReport( appointmentId: number, reportContent: Report, // Replace 'any' with a proper type for report content if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .put(`/admin/appointments/report/${appointmentId}`, reportContent) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getUpcomingAppointments( onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get("/admin/appointments/upcoming") .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function removeProject( projectId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .delete(`/admin/projects/${projectId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function grantAdminRights( userId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post(`/admin/make-admin/${userId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } // Shared API function getSectionCellsByDate( projectId: number, sectionId: number, date: string, // Use string for date in 'YYYY-MM-DD HH:mm' format onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(`/shared/projects/sectionCells/${projectId}/${sectionId}/${date}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getProjectEntrepreneurs( projectId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(`/shared/projects/entrepreneurs/${projectId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getProjectAdmin( projectId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(`/shared/projects/admin/${projectId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getProjectAppointments( projectId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(`/shared/projects/appointments/${projectId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function getAppointmentReport( appointmentId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .get(`/shared/appointments/report/${appointmentId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function requestAppointment( appointmentDetails: Appointment, // Replace 'any' with a proper type for appointment details if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post("/shared/appointments/request", appointmentDetails) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } // Entrepreneurs API function requestProjectCreation( projectDetails: Project, // Replace 'any' with a proper type for project details if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post("/entrepreneur/projects/request", projectDetails) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function addSectionCell( sectionCellDetails: SectionCell, // Replace 'any' with a proper type for section cell details if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .post("/entrepreneur/sectionCells", sectionCellDetails) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function modifySectionCell( sectionCellId: number, sectionCellDetails: SectionCell, // Replace 'any' with a proper type for section cell details if available onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .put(`/entrepreneur/sectionCells/${sectionCellId}`, sectionCellDetails) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } function removeSectionCell( sectionCellId: number, onSuccessHandler?: (response: AxiosResponse) => void, onErrorHandler?: (error: AxiosError) => void ): void { axiosInstance .delete(`/entrepreneur/sectionCells/${sectionCellId}`) .then((response) => { if (onSuccessHandler) { onSuccessHandler(response); } else { defaultApiSuccessHandler(response); } }) .catch((error: AxiosError) => { if (onErrorHandler) { onErrorHandler(error); } else { defaultApiErrorHandler(error); } }); } export { axiosInstance, callApi, postApi, deleteApi, finalizeAccount, // requestJoinProject, // Not yet implemented [cite: 4] getPendingAccounts, validateUserAccount, // getPendingProjectJoinRequests, // Not yet implemented [cite: 3] // decideProjectJoinRequest, // Not yet implemented [cite: 3] getAdminProjects, addProjectManually, getPendingProjects, decidePendingProject, createAppointmentReport, updateAppointmentReport, getUpcomingAppointments, removeProject, grantAdminRights, getSectionCellsByDate, getProjectEntrepreneurs, getProjectAdmin, getProjectAppointments, getAppointmentReport, requestAppointment, requestProjectCreation, addSectionCell, modifySectionCell, removeSectionCell, };