// API Configuration // Use relative URLs by default so it works with any domain/reverse proxy export const API_BASE_URL = (import.meta as any).env.VITE_API_URL || ''; // API Error class export class ApiError extends Error { constructor( message: string, public status?: number, public code?: string, public details?: unknown ) { super(message); this.name = 'ApiError'; } } // Helper function for API calls with error handling export const apiCall = async (endpoint: string, options?: RequestInit) => { const url = endpoint.startsWith('/') ? `${API_BASE_URL}${endpoint}` : endpoint; // Get auth token from localStorage const authToken = localStorage.getItem('authToken'); // Build headers const headers: HeadersInit = { 'Content-Type': 'application/json', ...options?.headers, }; // Add authorization header if token exists if (authToken) { headers['Authorization'] = `Bearer ${authToken}`; } try { const response = await fetch(url, { ...options, headers, }); // Handle non-2xx responses if (!response.ok) { let errorData; try { errorData = await response.json(); } catch { errorData = { error: { message: response.statusText } }; } throw new ApiError( errorData.error?.message || `Request failed with status ${response.status}`, response.status, errorData.error?.code, errorData.error?.details ); } // Try to parse JSON response const contentType = response.headers.get('content-type'); if (contentType && contentType.includes('application/json')) { const data = await response.json(); return { response, data }; } return { response, data: null }; } catch (error) { // Network errors or other issues if (error instanceof ApiError) { throw error; } throw new ApiError( error instanceof Error ? error.message : 'Network request failed', undefined, 'NETWORK_ERROR' ); } };