/** * QuadrantX Dashboard - API Client Module * * Handles all API calls with authentication. */ class ApiClient { constructor(config, authManager) { this.config = config; this.auth = authManager; } /** * Make authenticated API request */ async request(endpoint, options = {}) { const url = `${this.config.API_ENDPOINT}${endpoint}`; const headers = { 'Content-Type': 'application/json', ...options.headers }; // Add authorization header const token = this.auth.getIdToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } try { const response = await fetch(url, { ...options, headers }); if (response.status === 401) { // Token expired, try refresh const refreshed = await this.auth.refreshTokens(); if (refreshed) { headers['Authorization'] = `Bearer ${this.auth.getIdToken()}`; return fetch(url, { ...options, headers }).then(r => r.json()); } else { // Redirect to login this.auth.login(); throw new Error('Session expired'); } } if (response.status === 403) { const error = await response.json(); throw new Error(error.message || 'Access denied'); } if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'API error'); } return await response.json(); } catch (error) { console.error('API request error:', error); throw error; } } /** * Get categories */ async getCategories(showHidden = false) { const params = new URLSearchParams(); if (showHidden) params.set('show_hidden', 'true'); return this.request(`/api/categories?${params}`); } /** * Get vendors for a category */ async getVendors(categoryId, options = {}) { const params = new URLSearchParams({ category_id: categoryId }); if (options.startDate) params.set('start_date', options.startDate); if (options.endDate) params.set('end_date', options.endDate); if (options.showHidden) params.set('show_hidden', 'true'); if (options.sortBy) params.set('sort_by', options.sortBy); return this.request(`/api/vendors?${params}`); } /** * Get vendor scores for charting */ async getVendorScores(categoryId, vendorIds, options = {}) { const params = new URLSearchParams({ category_id: categoryId, vendor_ids: vendorIds.join(',') }); if (options.startDate) params.set('start_date', options.startDate); if (options.endDate) params.set('end_date', options.endDate); if (options.model) params.set('model', options.model); if (options.showHidden) params.set('show_hidden', 'true'); return this.request(`/api/vendor-scores?${params}`); } /** * Get category summary */ async getCategorySummary(categoryId, options = {}) { const params = new URLSearchParams({ category_id: categoryId }); if (options.startDate) params.set('start_date', options.startDate); if (options.endDate) params.set('end_date', options.endDate); if (options.showHidden) params.set('show_hidden', 'true'); return this.request(`/api/category-summary?${params}`); } /** * Get models for a category */ async getModels(categoryId, options = {}) { const params = new URLSearchParams({ category_id: categoryId }); if (options.startDate) params.set('start_date', options.startDate); if (options.endDate) params.set('end_date', options.endDate); if (options.showHidden) params.set('show_hidden', 'true'); return this.request(`/api/models?${params}`); } /** * Get report vendor detail */ async getReportVendorDetail(reportId, vendorId) { const params = new URLSearchParams({ report_id: reportId, vendor_id: vendorId }); return this.request(`/api/report-vendor-detail?${params}`); } } // Export for use in app window.ApiClient = ApiClient;