Spaces:
Configuration error
Configuration error
| import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' | |
| import { ApiResponse } from '../../../shared/types' | |
| class ApiService { | |
| private api: AxiosInstance | |
| constructor() { | |
| this.api = axios.create({ | |
| baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3001', | |
| timeout: 10000, | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| }) | |
| // Request interceptor to add auth token | |
| this.api.interceptors.request.use( | |
| (config) => { | |
| const token = this.getToken() | |
| if (token) { | |
| config.headers.Authorization = `Bearer ${token}` | |
| } | |
| return config | |
| }, | |
| (error) => { | |
| return Promise.reject(error) | |
| } | |
| ) | |
| // Response interceptor to handle errors | |
| this.api.interceptors.response.use( | |
| (response) => { | |
| return response | |
| }, | |
| (error) => { | |
| if (error.response?.status === 401) { | |
| // Token expired or invalid | |
| this.clearToken() | |
| window.location.href = '/login' | |
| } | |
| return Promise.reject(this.handleError(error)) | |
| } | |
| ) | |
| } | |
| private getToken(): string | null { | |
| try { | |
| const authStorage = localStorage.getItem('auth-storage') | |
| if (authStorage) { | |
| const parsed = JSON.parse(authStorage) | |
| return parsed.state?.token || null | |
| } | |
| } catch (error) { | |
| console.error('Error getting token:', error) | |
| } | |
| return null | |
| } | |
| private clearToken(): void { | |
| try { | |
| localStorage.removeItem('auth-storage') | |
| } catch (error) { | |
| console.error('Error clearing token:', error) | |
| } | |
| } | |
| private handleError(error: any): Error { | |
| if (error.response) { | |
| // Server responded with error status | |
| const message = error.response.data?.message || error.response.data?.error || 'Server error' | |
| return new Error(message) | |
| } else if (error.request) { | |
| // Request was made but no response received | |
| return new Error('Network error - please check your connection') | |
| } else { | |
| // Something else happened | |
| return new Error(error.message || 'An unexpected error occurred') | |
| } | |
| } | |
| // Generic request methods | |
| async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> { | |
| const response = await this.api.get<ApiResponse<T>>(url, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Request failed') | |
| } | |
| return response.data.data! | |
| } | |
| async post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> { | |
| const response = await this.api.post<ApiResponse<T>>(url, data, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Request failed') | |
| } | |
| return response.data.data! | |
| } | |
| async put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> { | |
| const response = await this.api.put<ApiResponse<T>>(url, data, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Request failed') | |
| } | |
| return response.data.data! | |
| } | |
| async patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> { | |
| const response = await this.api.patch<ApiResponse<T>>(url, data, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Request failed') | |
| } | |
| return response.data.data! | |
| } | |
| async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> { | |
| const response = await this.api.delete<ApiResponse<T>>(url, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Request failed') | |
| } | |
| return response.data.data! | |
| } | |
| // File upload method | |
| async upload<T>(url: string, file: File, onProgress?: (progress: number) => void): Promise<T> { | |
| const formData = new FormData() | |
| formData.append('file', file) | |
| const config: AxiosRequestConfig = { | |
| headers: { | |
| 'Content-Type': 'multipart/form-data', | |
| }, | |
| onUploadProgress: (progressEvent) => { | |
| if (onProgress && progressEvent.total) { | |
| const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total) | |
| onProgress(progress) | |
| } | |
| }, | |
| } | |
| const response = await this.api.post<ApiResponse<T>>(url, formData, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Upload failed') | |
| } | |
| return response.data.data! | |
| } | |
| // Multiple file upload method | |
| async uploadMultiple<T>( | |
| url: string, | |
| files: File[], | |
| onProgress?: (progress: number) => void | |
| ): Promise<T> { | |
| const formData = new FormData() | |
| files.forEach((file, index) => { | |
| formData.append(`files[${index}]`, file) | |
| }) | |
| const config: AxiosRequestConfig = { | |
| headers: { | |
| 'Content-Type': 'multipart/form-data', | |
| }, | |
| onUploadProgress: (progressEvent) => { | |
| if (onProgress && progressEvent.total) { | |
| const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total) | |
| onProgress(progress) | |
| } | |
| }, | |
| } | |
| const response = await this.api.post<ApiResponse<T>>(url, formData, config) | |
| if (!response.data.success) { | |
| throw new Error(response.data.error || 'Upload failed') | |
| } | |
| return response.data.data! | |
| } | |
| // Get raw axios instance for custom requests | |
| getAxiosInstance(): AxiosInstance { | |
| return this.api | |
| } | |
| } | |
| export const apiService = new ApiService() | |