import type { SleepSessionCreate, SleepSessionUpdate, SleepSessionRead, SessionListResponse, DailySummaryResponse, TimetableResponse, WakeupBedtimeResponse, SummaryResponse } from '@/types'; const BASE_URL = import.meta.env.VITE_API_BASE_URL || ''; /** * Convert a local HH:MM time string to its UTC equivalent. * @param hhmm - Local time as "HH:MM" * @returns UTC time as "HH:MM" */ export function localHHMMToUTCHHMM(hhmm: string): string { const [hours, minutes] = hhmm.split(":").map(Number); const offsetInMinutes = new Date().getTimezoneOffset(); // UTC = Local - offsetInMinutes (where offset is negative for East of UTC) const totalMinutesUTC = (hours * 60 + minutes) + offsetInMinutes; const normalizedMinutes = ((totalMinutesUTC % 1440) + 1440) % 1440; const h = Math.floor(normalizedMinutes / 60); const m = normalizedMinutes % 60; return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`; } export function localToUTC(localValue: string): string { return new Date(localValue).toISOString(); } async function fetchStats(endpoint: string, from_date: string, to_date: string, extraParams: Record = {}): Promise { const params = new URLSearchParams({ from_date, to_date, ...extraParams }); const response = await fetch(`${BASE_URL}/api/stats/${endpoint}?${params.toString()}`); if (!response.ok) throw new Error(`Failed to fetch ${endpoint}`); return response.json(); } export async function fetchSummary(from_date: string, to_date: string): Promise { return fetchStats('summary', from_date, to_date); } export async function fetchDailySummary(from_date: string, to_date: string, day_start: string, day_end: string, timezone_offset = 0): Promise { return fetchStats('daily-summary', from_date, to_date, { day_start, day_end, timezone_offset: timezone_offset.toString() }); } export async function fetchTimetable(from_date: string, to_date: string, day_start: string, day_end: string, timezone_offset = 0): Promise { return fetchStats('timetable', from_date, to_date, { day_start, day_end, timezone_offset: timezone_offset.toString() }); } export async function fetchWakeSleepTimes(from_date: string, to_date: string, wakeup_ref: string, bedtime_ref: string, timezone_offset = 0): Promise { return fetchStats('wake-sleep-times', from_date, to_date, { wakeup_ref: localHHMMToUTCHHMM(wakeup_ref), bedtime_ref: localHHMMToUTCHHMM(bedtime_ref), timezone_offset: timezone_offset.toString() }); } // Session API functions export async function fetchActiveSession(): Promise { const response = await fetch(`${BASE_URL}/api/sessions/active`); if (!response.ok) return null; return response.json(); } export async function fetchSessions(): Promise { const response = await fetch(`${BASE_URL}/api/sessions`); if (!response.ok) throw new Error('Failed to fetch sessions'); return response.json(); } export async function createSession(payload: SleepSessionCreate): Promise { const response = await fetch(`${BASE_URL}/api/sessions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!response.ok) throw new Error('Failed to create session'); return response.json(); } export async function endSession(sessionId: number, payload: SleepSessionUpdate): Promise { const response = await fetch(`${BASE_URL}/api/sessions/${sessionId}/end`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!response.ok) throw new Error('Failed to end session'); return response.json(); } export async function deleteSession(sessionId: number): Promise { const response = await fetch(`${BASE_URL}/api/sessions/${sessionId}`, { method: 'DELETE', }); if (!response.ok) throw new Error('Failed to delete session'); } export async function updateSession(sessionId: number, payload: SleepSessionUpdate): Promise { const response = await fetch(`${BASE_URL}/api/sessions/${sessionId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!response.ok) throw new Error('Failed to update session'); return response.json(); }