/** * API Service * * Axios configuration and API client for backend communication */ import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios'; const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000/api/v1'; // Create axios instance const apiClient: AxiosInstance = axios.create({ baseURL: API_URL, headers: { 'Content-Type': 'application/json', }, }); // Request interceptor to add auth token apiClient.interceptors.request.use( (config: InternalAxiosRequestConfig) => { const token = localStorage.getItem('access_token'); if (token && config.headers) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); // Response interceptor for error handling apiClient.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; // Handle 401 errors (token expired) if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const refreshToken = localStorage.getItem('refresh_token'); if (refreshToken) { const response = await axios.post(`${API_URL}/auth/refresh`, { refresh_token: refreshToken, }); const { access_token } = response.data; localStorage.setItem('access_token', access_token); // Retry original request with new token originalRequest.headers.Authorization = `Bearer ${access_token}`; return apiClient(originalRequest); } } catch (refreshError) { // Refresh failed, clear tokens and redirect to login localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/'; return Promise.reject(refreshError); } } return Promise.reject(error); } ); export default apiClient; // API methods export const authAPI = { login: (idToken: string) => apiClient.post('/auth/login', { id_token: idToken }), loginSimple: (email: string, password: string) => apiClient.post('/auth/login/simple', { email, password }), logout: () => apiClient.post('/auth/logout'), getCurrentUser: () => apiClient.get('/auth/me'), refreshToken: (refreshToken: string) => apiClient.post('/auth/refresh', { refresh_token: refreshToken }), }; export const conversationAPI = { list: (includeArchived: boolean = false, skip: number = 0, limit: number = 50) => apiClient.get('/conversations', { params: { include_archived: includeArchived, skip, limit }, }), create: (title?: string) => apiClient.post('/conversations', { title }), get: (id: string) => apiClient.get(`/conversations/${id}`), update: (id: string, title: string) => apiClient.put(`/conversations/${id}`, { title }), archive: (id: string) => apiClient.post(`/conversations/${id}/archive`), delete: (id: string) => apiClient.delete(`/conversations/${id}`), }; export const messageAPI = { list: (conversationId: string, skip: number = 0, limit: number = 100) => apiClient.get(`/conversations/${conversationId}/messages`, { params: { skip, limit }, }), send: (conversationId: string, content: string) => apiClient.post(`/conversations/${conversationId}/messages`, { content }), }; export const tokenAPI = { getUsage: (days: number = 30) => apiClient.get('/tokens/usage', { params: { days } }), getUsersUsage: (days: number = 30) => apiClient.get('/tokens/users', { params: { days } }), getDailyUsageByUser: (days: number = 30) => apiClient.get('/tokens/daily-users', { params: { days } }), }; export const adminAPI = { // User management listUsers: (skip: number = 0, limit: number = 100) => apiClient.get('/admin/users', { params: { skip, limit } }), updateUserRole: (userId: string, role: string) => apiClient.put(`/admin/users/${userId}/role`, { role }), activateUser: (userId: string) => apiClient.put(`/admin/users/${userId}/activate`), deactivateUser: (userId: string) => apiClient.put(`/admin/users/${userId}/deactivate`), // Analytics getSystemAnalytics: () => apiClient.get('/admin/analytics/system'), getUsersAnalytics: (days: number = 30, limit: number = 50) => apiClient.get('/admin/analytics/users', { params: { days, limit } }), getAllConversations: (skip: number = 0, limit: number = 50) => apiClient.get('/admin/conversations/all', { params: { skip, limit } }), };