136 lines
4.8 KiB
JavaScript
136 lines
4.8 KiB
JavaScript
import axios from 'axios'
|
|
import toast from 'react-hot-toast'
|
|
|
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1'
|
|
|
|
// Create axios instance
|
|
export const api = axios.create({
|
|
baseURL: API_BASE_URL,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
})
|
|
|
|
// Request interceptor to add auth token
|
|
api.interceptors.request.use(
|
|
(config) => {
|
|
const token = localStorage.getItem('accessToken')
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`
|
|
}
|
|
return config
|
|
},
|
|
(error) => {
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
// Response interceptor to handle token refresh
|
|
api.interceptors.response.use(
|
|
(response) => response,
|
|
async (error) => {
|
|
const originalRequest = error.config
|
|
|
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
originalRequest._retry = true
|
|
|
|
try {
|
|
const refreshToken = localStorage.getItem('refreshToken')
|
|
if (refreshToken) {
|
|
const response = await axios.post(`${API_BASE_URL}/auth/refresh/`, {
|
|
refresh: refreshToken,
|
|
})
|
|
|
|
const { access } = response.data
|
|
localStorage.setItem('accessToken', access)
|
|
|
|
// Retry original request with new token
|
|
originalRequest.headers.Authorization = `Bearer ${access}`
|
|
return api(originalRequest)
|
|
} else {
|
|
// No refresh token, clear everything and redirect
|
|
localStorage.removeItem('accessToken')
|
|
localStorage.removeItem('refreshToken')
|
|
// Only redirect if not already on login page
|
|
if (window.location.pathname !== '/login') {
|
|
window.location.href = '/login'
|
|
}
|
|
}
|
|
} catch (refreshError) {
|
|
// Refresh failed, clear tokens but don't redirect if already on login
|
|
localStorage.removeItem('accessToken')
|
|
localStorage.removeItem('refreshToken')
|
|
if (window.location.pathname !== '/login') {
|
|
window.location.href = '/login'
|
|
}
|
|
return Promise.reject(refreshError)
|
|
}
|
|
}
|
|
|
|
// Handle other errors
|
|
if (error.response?.status >= 500) {
|
|
toast.error('Server error. Please try again later.')
|
|
} else if (error.response?.status === 403) {
|
|
toast.error('Access denied. You do not have permission to perform this action.')
|
|
} else if (error.response?.status === 404) {
|
|
toast.error('Resource not found.')
|
|
} else if (error.response?.data?.message) {
|
|
toast.error(error.response.data.message)
|
|
} else if (error.message) {
|
|
toast.error(error.message)
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
// API endpoints
|
|
export const authAPI = {
|
|
login: (credentials) => api.post('/auth/login/', credentials),
|
|
register: (userData) => api.post('/auth/register/', userData),
|
|
logout: () => api.post('/auth/logout/'),
|
|
refresh: (refreshToken) => api.post('/auth/refresh/', { refresh: refreshToken }),
|
|
getUser: () => api.get('/auth/user/'),
|
|
updateUser: (userData) => api.patch('/auth/update/', userData),
|
|
changePassword: (passwordData) => api.post('/auth/change-password/', passwordData),
|
|
}
|
|
|
|
export const analyticsAPI = {
|
|
getTransactions: (params) => api.get('/analytics/transactions/', { params }),
|
|
getTransactionSummary: (params) => api.get('/analytics/summary/', { params }),
|
|
getAreaStats: (params) => api.get('/analytics/area-stats-data/', { params }),
|
|
getPropertyTypeStats: (params) => api.get('/analytics/property-type-stats/', { params }),
|
|
getTimeSeriesData: (params) => api.get('/analytics/time-series-data/', { params }),
|
|
getMarketAnalysis: (params) => api.get('/analytics/market-analysis/', { params }),
|
|
generateForecast: (data) => api.post('/analytics/forecast/', data),
|
|
}
|
|
|
|
export const reportsAPI = {
|
|
getReports: (params) => api.get('/reports/', { params }),
|
|
getReport: (id) => api.get(`/reports/${id}/`),
|
|
generateTransactionSummary: (data) => api.post('/reports/generate/transaction-summary/', data),
|
|
generateAreaAnalysis: (data) => api.post('/reports/generate/area-analysis/', data),
|
|
generateForecast: (data) => api.post('/reports/generate/forecast/', data),
|
|
downloadReport: (id) => api.get(`/reports/${id}/download/`, { responseType: 'blob' }),
|
|
}
|
|
|
|
export const usersAPI = {
|
|
getUsers: (params) => api.get('/auth/list/', { params }),
|
|
getUser: (id) => api.get(`/auth/${id}/`),
|
|
updateUser: (id, data) => api.patch(`/auth/${id}/`, data),
|
|
updateSubscription: (data) => api.post('/auth/update-subscription/', data),
|
|
toggleApiAccess: (data) => api.post('/auth/toggle-api-access/', data),
|
|
regenerateApiKey: () => api.post('/auth/regenerate-api-key/'),
|
|
}
|
|
|
|
export const billingAPI = {
|
|
getUsageStats: () => api.get('/billing/usage/'),
|
|
getSubscriptionInfo: () => api.get('/billing/subscription/'),
|
|
}
|
|
|
|
export const monitoringAPI = {
|
|
getMetrics: () => api.get('/monitoring/metrics/'),
|
|
getHealthCheck: () => api.get('/monitoring/health/'),
|
|
}
|
|
|