110 lines
4.3 KiB
TypeScript
110 lines
4.3 KiB
TypeScript
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<T>(endpoint: string, from_date: string, to_date: string, extraParams: Record<string, string> = {}): Promise<T> {
|
|
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<SummaryResponse> {
|
|
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<DailySummaryResponse> {
|
|
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<TimetableResponse> {
|
|
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<WakeupBedtimeResponse> {
|
|
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<SleepSessionRead | null> {
|
|
const response = await fetch(`${BASE_URL}/api/sessions/active`);
|
|
if (!response.ok) return null;
|
|
return response.json();
|
|
}
|
|
|
|
export async function fetchSessions(): Promise<SessionListResponse> {
|
|
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<SleepSessionRead> {
|
|
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<SleepSessionRead> {
|
|
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<void> {
|
|
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<SleepSessionRead> {
|
|
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();
|
|
}
|