import axios from "axios"; const api = axios.create({ baseURL: import.meta.env.VITE_API_URL || "https://habib-analyst-email-agent-api.hf.space/api", headers: { "Content-Type": "application/json" }, timeout: 180000, }); // ─── Token Management ────────────────────────────────────────────── let _token = null; export function setAuthToken(token) { _token = token; if (token) { sessionStorage.setItem("session_token", token); } else { sessionStorage.removeItem("session_token"); } } export function getAuthToken() { if (!_token) { _token = sessionStorage.getItem("session_token"); } return _token; } export function clearAuthToken() { _token = null; sessionStorage.removeItem("session_token"); } // ─── Attach JWT to every request ─────────────────────────────────── api.interceptors.request.use((config) => { const token = getAuthToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // ─── Handle 401 responses globally ───────────────────────────────── api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { // Don't redirect if we're already on auth routes const url = error.config?.url || ""; if (!url.includes("/auth/") && !url.includes("/admin/login")) { clearAuthToken(); // Dispatch a custom event so AuthContext can react window.dispatchEvent(new CustomEvent("auth:expired")); } } return Promise.reject(error); } ); export const authAPI = { getStatus: () => api.get("/auth/status"), startAuth: () => api.get("/auth/gmail"), disconnect: () => api.post("/auth/disconnect"), }; export const adminAPI = { login: (email, password) => api.post("/admin/login", { email, password }), getStats: () => api.get("/admin/stats"), getUsers: () => api.get("/admin/users"), userAction: (email, action) => api.post("/admin/users/action", { email, action }), }; export const quotaAPI = { getStatus: () => api.get("/quota/status"), checkDuplicate: (recipientEmail) => api.get(`/quota/check-duplicate/${recipientEmail}`), }; export const emailAPI = { loadTemplate: () => api.post("/email/load-template"), applyTemplate: (recipientInput) => api.post("/email/apply-template", { professor_input: recipientInput }), verify: (toEmail, subject, htmlBody) => api.post("/email/verify", { to_email: toEmail, subject, html_body: htmlBody }), send: (toEmail, subject, htmlBody) => api.post("/email/send", { to_email: toEmail, subject, html_body: htmlBody }), getAttachments: () => api.get("/email/attachments"), uploadAttachment: (file) => { const form = new FormData(); form.append("file", file); return api.post("/email/attachments/upload", form, { headers: { "Content-Type": "multipart/form-data" }, }); }, deleteAttachment: (filename) => api.delete(`/email/attachments/${filename}`), contactSales: (data) => api.post("/email/contact-sales", data), }; export const batchAPI = { uploadCSV: (file) => { const form = new FormData(); form.append("file", file); return api.post("/batch/upload-csv", form, { headers: { "Content-Type": "multipart/form-data" }, }); }, extractEmails: (text) => api.post("/batch/extract-emails", { text }), scrapeFaculty: (url) => api.post("/batch/scrape-faculty", { url }, { timeout: 120000 }), start: (recipientList, mode = "manual", delayMin = 15, delayMax = 45) => api.post("/batch/start", { professor_list: recipientList, mode, delay_min: delayMin, delay_max: delayMax, }), getQueue: () => api.get("/batch/queue"), generate: (index) => api.post(`/batch/generate/${index}`), send: (index) => api.post(`/batch/send/${index}`), skip: (index) => api.post(`/batch/skip/${index}`), autoRun: () => api.post("/batch/auto-run", {}, { timeout: 3600000 }), stop: () => api.post("/batch/stop"), clear: () => api.post("/batch/clear"), }; export default api;