| import axios from 'axios' |
|
|
| |
| const api = axios.create({ |
| baseURL: import.meta.env.VITE_API_URL || 'http://localhost:5000/api', |
| headers: { |
| 'Content-Type': 'application/json' |
| }, |
| |
| adapter: 'xhr', |
| withCredentials: true |
| }) |
|
|
| |
| api.defaults.timeout = 10000 |
|
|
| |
| const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development' |
| const isProduction = import.meta.env.VITE_NODE_ENV === 'production' |
|
|
| |
| const logApiCall = (config) => { |
| if (isDevelopment) { |
| console.log(`π [API] ${config.method?.toUpperCase()} ${config.url}`, { |
| data: config.data, |
| params: config.params, |
| headers: config.headers |
| }) |
| } |
| } |
|
|
| |
| const logApiError = (error) => { |
| if (isDevelopment) { |
| console.error(`β [API Error] ${error.config?.url || 'Unknown URL'}`, { |
| status: error.response?.status, |
| statusText: error.response?.statusText, |
| data: error.response?.data, |
| message: error.message |
| }) |
| } |
| } |
|
|
| |
| api.interceptors.request.use( |
| (config) => { |
| |
| logApiCall(config) |
| |
| const token = localStorage.getItem('token') |
| if (token) { |
| config.headers.Authorization = `Bearer ${token}` |
| } |
| return config |
| }, |
| (error) => { |
| logApiError(error) |
| return Promise.reject(error) |
| } |
| ) |
|
|
| |
| api.interceptors.request.use( |
| async (config) => { |
| const token = localStorage.getItem('token') |
| if (token) { |
| try { |
| |
| const tokenData = JSON.parse(atob(token.split('.')[1])) |
| const isExpired = tokenData.exp * 1000 < Date.now() |
| |
| if (isExpired) { |
| |
| localStorage.removeItem('token') |
| if (isDevelopment) { |
| console.log('π [Token] Token expired, removed from storage') |
| } |
| |
| |
| if (!window.location.pathname.includes('/login')) { |
| window.location.href = '/login' |
| } |
| } else { |
| |
| config.headers.Authorization = `Bearer ${token}` |
| } |
| } catch (error) { |
| |
| localStorage.removeItem('token') |
| if (isDevelopment) { |
| console.log('π [Token] Invalid token format, removed from storage') |
| } |
| |
| |
| if (!window.location.pathname.includes('/login')) { |
| window.location.href = '/login' |
| } |
| } |
| } |
| return config |
| }, |
| (error) => { |
| logApiError(error) |
| return Promise.reject(error) |
| } |
| ) |
|
|
| |
| api.interceptors.response.use( |
| (response) => { |
| if (isDevelopment) { |
| console.log(`β
[API Response] ${response.config.url}`, { |
| status: response.status, |
| data: response.data |
| }) |
| } |
| return response |
| }, |
| (error) => { |
| logApiError(error) |
| |
| if (error.response?.status === 401) { |
| |
| if (!window.location.pathname.includes('/login')) { |
| localStorage.removeItem('token') |
| window.location.href = '/login' |
| } |
| } |
| |
| |
| if (error.response) { |
| |
| |
| const status = error.response.status |
| const data = error.response.data |
| |
| if (isDevelopment) { |
| console.error(`π¨ [API Error ${status}]`, { |
| url: error.config.url, |
| method: error.config.method, |
| data: data, |
| headers: error.response.headers |
| }) |
| } |
| } else if (error.request) { |
| |
| if (isDevelopment) { |
| console.error('π¨ [Network Error] No response received:', { |
| url: error.config?.url, |
| message: error.message |
| }) |
| } |
| } else { |
| |
| if (isDevelopment) { |
| console.error('π¨ [Request Error]', error.message) |
| } |
| } |
| |
| return Promise.reject(error) |
| } |
| ) |
|
|
| export default api |