Spaces:
Sleeping
Sleeping
| import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; | |
| import { API_BASE_URL } from '../../config'; | |
| import { getSystemHealth } from './health'; | |
| // Mobile platform detection (simpler approach without Capacitor dependency) | |
| const isMobileApp = () => { | |
| return typeof window !== 'undefined' && | |
| (window.location.href.includes('capacitor://') || | |
| window.location.href.includes('ionic://') || | |
| /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)); | |
| }; | |
| const isNative = isMobileApp(); | |
| // Create a custom axios instance | |
| const apiClient = axios.create({ | |
| baseURL: API_BASE_URL, | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| // Add additional headers for mobile apps | |
| ...(isNative && { | |
| 'X-Requested-With': 'XMLHttpRequest', | |
| 'X-Mobile-App': 'true' | |
| }) | |
| }, | |
| timeout: 30000, // 30 seconds timeout | |
| withCredentials: false // Disable withCredentials which can cause CORS issues | |
| }); | |
| // Request interceptor to handle authentication for all requests | |
| apiClient.interceptors.request.use( | |
| (config: InternalAxiosRequestConfig) => { | |
| // Get token from user_session in localStorage | |
| const userSession = localStorage.getItem('user_session'); | |
| // Add detailed debugging | |
| console.log(`API Request to: ${config.url}`); | |
| console.log(`Method: ${config.method?.toUpperCase()}`); | |
| console.log(`Running on platform: ${isNative ? 'Mobile' : 'Web'}`); | |
| // If session exists, parse it and add token to headers | |
| if (userSession) { | |
| try { | |
| const userData = JSON.parse(userSession); | |
| console.log(`User session found: ${userData.firstName} ${userData.lastName} (${userData.email})`); | |
| if (userData && userData.token) { | |
| // Set Authorization header for all requests | |
| config.headers.Authorization = `Bearer ${userData.token}`; | |
| console.log(`Token applied: ${userData.token.substring(0, 15)}...`); | |
| } else { | |
| console.warn('Token missing in user session! Session data:', JSON.stringify(userData, null, 2)); | |
| } | |
| } catch (error) { | |
| console.error('Error parsing user session:', error); | |
| } | |
| } else { | |
| console.warn('No user_session found in localStorage - request will be unauthorized'); | |
| } | |
| // Log final headers for debugging | |
| // console.log('Request headers:', JSON.stringify(config.headers, null, 2)); | |
| // console.log('Request URL (full):', `${config.baseURL}${config.url}`); | |
| return config; | |
| }, | |
| (error: AxiosError) => { | |
| // Handle request errors | |
| console.error('Request error:', error); | |
| return Promise.reject(error); | |
| } | |
| ); | |
| // Special interceptor for the health endpoint | |
| apiClient.interceptors.response.use( | |
| (response: AxiosResponse) => { | |
| const url = response.config.url; | |
| // Check if this is a health endpoint request | |
| if (url && (url === '/health' || url.endsWith('/health') || url === '/api/health' || url.endsWith('/api/health'))) { | |
| console.log('Health endpoint detected, returning custom health response'); | |
| // Use the shared health implementation from health.ts | |
| response.data = getSystemHealth(); | |
| } | |
| return response; | |
| }, | |
| (error) => Promise.reject(error) | |
| ); | |
| // Response interceptor to handle authentication-related responses | |
| apiClient.interceptors.response.use( | |
| (response: AxiosResponse) => { | |
| // Any status code within the range of 2xx causes this function to trigger | |
| return response; | |
| }, | |
| async (error: AxiosError) => { | |
| const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean }; | |
| // Handle 401 Unauthorized errors | |
| if (error.response?.status === 401 && !originalRequest._retry) { | |
| // Since we're using user_session, update refresh token logic accordingly | |
| const userSession = localStorage.getItem('user_session'); | |
| if (userSession) { | |
| originalRequest._retry = true; | |
| try { | |
| // Here you could implement token refresh logic | |
| // Example (commented out): | |
| /* | |
| const userData = JSON.parse(userSession); | |
| // Call your refresh token API | |
| const response = await apiClient.post( | |
| `${API_BASE_URL}/auth/refresh-token`, | |
| { | |
| userId: userData.userId, | |
| // Include any other required fields | |
| }, | |
| { | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| } | |
| } | |
| ); | |
| if (response.data && response.data.token) { | |
| // Update the token in localStorage | |
| userData.token = response.data.token; | |
| localStorage.setItem('user_session', JSON.stringify(userData)); | |
| // Retry the original request with new token | |
| originalRequest.headers.Authorization = `Bearer ${response.data.token}`; | |
| return apiClient(originalRequest); | |
| } | |
| */ | |
| // For now, just clear the session and redirect to login | |
| localStorage.removeItem('user_session'); | |
| // Redirect to login page | |
| window.location.href = '/login'; | |
| return Promise.reject(error); | |
| } catch (refreshError) { | |
| // If any error during this process, clear session and redirect | |
| localStorage.removeItem('user_session'); | |
| // Redirect to login page | |
| window.location.href = '/login'; | |
| return Promise.reject(refreshError); | |
| } | |
| } else { | |
| // No session available, redirect to login | |
| window.location.href = '/login'; | |
| } | |
| } | |
| // Handle 403 Forbidden errors (permissions issue) | |
| if (error.response?.status === 403) { | |
| console.error('Forbidden resource:', error.config?.url); | |
| // You can implement specific handling for forbidden resources | |
| // For example, show an access denied notification or redirect | |
| // window.location.href = '/access-denied'; | |
| } | |
| // Handle 404 Not Found errors | |
| if (error.response?.status === 404) { | |
| console.error('Resource not found:', error.config?.url); | |
| } | |
| // Handle 500 and other server errors | |
| if (error.response?.status && error.response.status >= 500) { | |
| console.error('Server error:', error.response.status, error.config?.url); | |
| // Optionally show a server error notification | |
| } | |
| // Network errors | |
| if (error.message === 'Network Error') { | |
| console.error('Network error - check internet connection'); | |
| // Optionally show a network error notification | |
| } | |
| // Timeout errors | |
| if (error.code === 'ECONNABORTED') { | |
| console.error('Request timeout'); | |
| // Optionally show a timeout error notification | |
| } | |
| return Promise.reject(error); | |
| } | |
| ); | |
| export default apiClient; | |