| | const API_BASE = '/api' |
| |
|
| | class ApiError extends Error { |
| | constructor(message, status, data) { |
| | super(message) |
| | this.status = status |
| | this.data = data |
| | } |
| | } |
| |
|
| | async function request(endpoint, options = {}) { |
| | const url = `${API_BASE}${endpoint}` |
| |
|
| | const config = { |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | ...options.headers |
| | }, |
| | ...options |
| | } |
| |
|
| | try { |
| | const response = await fetch(url, config) |
| |
|
| | const data = await response.json() |
| |
|
| | if (!response.ok) { |
| | |
| | let message = 'Request failed' |
| | if (typeof data === 'object' && data !== null) { |
| | const errors = [] |
| | for (const [field, value] of Object.entries(data)) { |
| | if (Array.isArray(value)) { |
| | errors.push(...value) |
| | } else if (typeof value === 'string') { |
| | errors.push(value) |
| | } |
| | } |
| | if (errors.length > 0) { |
| | message = errors.join('. ') |
| | } else if (data.message) { |
| | message = data.message |
| | } |
| | } |
| |
|
| | throw new ApiError(message, response.status, data) |
| | } |
| |
|
| | return data |
| | } catch (error) { |
| | if (error instanceof ApiError) { |
| | throw error |
| | } |
| | throw new ApiError('Network error', 0, { originalError: error }) |
| | } |
| | } |
| |
|
| | export const api = { |
| | |
| | getProfiles: () => request('/profiles/'), |
| | getProfile: (id) => request(`/profiles/${id}/`), |
| |
|
| | |
| | runSimulation: (config, numTeams = 10, startDate) => request('/profiles/simulate/', { |
| | method: 'POST', |
| | body: JSON.stringify({ config, num_teams: numTeams, start_date: startDate }) |
| | }), |
| |
|
| | |
| | getProfileDays: (id, day) => request(`/profiles/${id}/days/${day}/`), |
| | getProfileOverview: (id, day) => request(`/profiles/${id}/overview/${day}/`), |
| | getOverviewByDay: (day) => request(`/profiles/overview/${day}/`), |
| | getOverviewTotal: () => request('/profiles/overview/') |
| | } |
| |
|