Files
common-availability/frontend/src/api/client.ts
2026-01-28 14:53:12 -05:00

118 lines
3.4 KiB
TypeScript

// Use VITE_API_URL if set at build time, otherwise derive from current origin
const API_URL = import.meta.env.VITE_API_URL || `${window.location.origin}/api`;
export interface ParticipantAPI {
id: string;
name: string;
email: string;
timezone: string;
ics_url: string | null;
created_at: string;
updated_at: string;
}
export interface TimeSlotAPI {
day: string;
hour: number;
start_time: string;
availability: 'full' | 'partial' | 'none';
availableParticipants: string[];
}
export interface CreateParticipantRequest {
name: string;
email: string;
timezone: string;
ics_url?: string;
}
export interface UpdateParticipantRequest {
timezone?: string;
ics_url?: string;
}
async function handleResponse<T>(response: Response): Promise<T> {
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: 'Request failed' }));
throw new Error(error.detail || 'Request failed');
}
return response.json();
}
export async function fetchParticipants(): Promise<ParticipantAPI[]> {
const response = await fetch(`${API_URL}/api/participants`);
return handleResponse<ParticipantAPI[]>(response);
}
export async function createParticipant(data: CreateParticipantRequest): Promise<ParticipantAPI> {
const response = await fetch(`${API_URL}/api/participants`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
return handleResponse<ParticipantAPI>(response);
}
export async function updateParticipant(id: string, data: UpdateParticipantRequest): Promise<ParticipantAPI> {
const response = await fetch(`${API_URL}/api/participants/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
return handleResponse<ParticipantAPI>(response);
}
export async function deleteParticipant(id: string): Promise<void> {
const response = await fetch(`${API_URL}/api/participants/${id}`, {
method: 'DELETE',
});
if (!response.ok) {
throw new Error('Failed to delete participant');
}
}
export async function fetchAvailability(participantIds: string[]): Promise<TimeSlotAPI[]> {
const response = await fetch(`${API_URL}/api/availability`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ participant_ids: participantIds }),
});
const data = await handleResponse<{ slots: TimeSlotAPI[] }>(response);
return data.slots;
}
export async function syncCalendars(): Promise<void> {
const response = await fetch(`${API_URL}/api/sync`, { method: 'POST' });
if (!response.ok) {
throw new Error('Failed to sync calendars');
}
}
export async function syncParticipant(id: string): Promise<void> {
const response = await fetch(`${API_URL}/api/sync/${id}`, { method: 'POST' });
if (!response.ok) {
throw new Error('Failed to sync participant calendar');
}
}
export async function scheduleMeeting(
participantIds: string[],
title: string,
description: string,
startTime: string,
endTime: string,
): Promise<{ email_sent: boolean; zulip_sent: boolean }> {
const response = await fetch(`${API_URL}/api/schedule`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
participant_ids: participantIds,
title,
description,
start_time: startTime,
end_time: endTime,
}),
});
return handleResponse(response);
}