import axios from 'axios' import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios' import { useNotificationStore } from '@/stores/useNotificationStore' import { useOrganisationStore } from '@/stores/useOrganisationStore' const apiClient: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_URL, withCredentials: true, headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, timeout: 30000, }) apiClient.interceptors.request.use( (config: InternalAxiosRequestConfig) => { const orgStore = useOrganisationStore() if (orgStore.activeOrganisationId) { config.headers['X-Organisation-Id'] = orgStore.activeOrganisationId } // Add impersonation header when active // Lazy import to avoid circular dependency with store const impersonationData = sessionStorage.getItem('crewli_impersonation') if (impersonationData) { try { const parsed = JSON.parse(impersonationData) as { targetUserId?: string } if (parsed.targetUserId) { config.headers['X-Impersonate-User'] = parsed.targetUserId } } catch { // Invalid data — ignore } } if (import.meta.env.DEV) { console.log(`🚀 ${config.method?.toUpperCase()} ${config.url}`, config.data) } return config }, error => Promise.reject(error), ) apiClient.interceptors.response.use( response => { if (import.meta.env.DEV) { console.log(`✅ ${response.status} ${response.config.url}`, response.data) } return response }, error => { if (import.meta.env.DEV) { console.error(`❌ ${error.response?.status} ${error.config?.url}`, error.response?.data) } const status = error.response?.status const notificationStore = useNotificationStore() // Handle impersonation session expiry if (status === 403 && error.response?.data?.impersonation_ended) { import('@/stores/useImpersonationStore').then(({ useImpersonationStore }) => { const impersonationStore = useImpersonationStore() impersonationStore.clearState() window.location.href = '/platform' }) return Promise.reject(error) } if (status === 401) { // Lazy import to avoid circular dependency import('@/stores/useAuthStore').then(({ useAuthStore }) => { const authStore = useAuthStore() if (authStore.isInitialized) { authStore.handleUnauthorized() } }) } else if (status === 403) { notificationStore.show('You don\'t have permission for this action.', 'error') } else if (status === 404) { notificationStore.show('The requested item was not found.', 'warning') } else if (status === 422) { // Show validation message to user; still reject so component onError handlers can react const message = error.response?.data?.message if (message && typeof message === 'string') { notificationStore.show(message, 'error') } } else if (status === 503) { notificationStore.show('Service temporarily unavailable. Please try again later.', 'error') } else if (status && status >= 500) { notificationStore.show('An unexpected error occurred. Please try again later.', 'error') } else if (!error.response) { // Network error — no response received notificationStore.show('Unable to connect to the server. Check your internet connection.', 'error') } return Promise.reject(error) }, ) export { apiClient }