Soon fixing timeone in wakeup plot

This commit is contained in:
2026-05-27 17:58:22 +02:00
parent 3e8a2092cd
commit fb709b4a2c
8 changed files with 340 additions and 45 deletions
+99 -1
View File
@@ -2,6 +2,22 @@ import type { SleepSessionCreate, SleepSessionUpdate, SleepSessionRead, SessionL
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();
}
@@ -24,7 +40,89 @@ export async function fetchTimetable(from_date: string, to_date: string, day_sta
}
export async function fetchWakeSleepTimes(from_date: string, to_date: string, wakeup_ref: string, bedtime_ref: string): Promise<any> {
return fetchStats('wake-sleep-times', from_date, to_date, { wakeup_ref, bedtime_ref });
return fetchStats('wake-sleep-times', from_date, to_date, {
wakeup_ref: localHHMMToUTCHHMM(wakeup_ref),
bedtime_ref: localHHMMToUTCHHMM(bedtime_ref)
});
}
// 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();
}
export function localToUTC(localValue: string): string {
return new Date(localValue).toISOString();
}
async function fetchStats(endpoint: string, from_date: string, to_date: string, extraParams: Record<string, string> = {}): Promise<any> {
const fromDT = new Date(`${from_date}T00:00:00`).toISOString();
const toDT = new Date(`${to_date}T23:59:59`).toISOString();
const params = new URLSearchParams({ from_date: fromDT, to_date: toDT, ...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 fetchDailySummary(from_date: string, to_date: string, day_start: string, day_end: string): Promise<any> {
return fetchStats('daily-summary', from_date, to_date, { day_start, day_end });
}
export async function fetchTimetable(from_date: string, to_date: string, day_start: string, day_end: string): Promise<any> {
return fetchStats('timetable', from_date, to_date, { day_start, day_end });
}
export async function fetchWakeSleepTimes(from_date: string, to_date: string, wakeup_ref: string, bedtime_ref: string): Promise<any> {
return fetchStats('wake-sleep-times', from_date, to_date, {
wakeup_ref: localHHMMToUTCHHMM(wakeup_ref),
bedtime_ref: localHHMMToUTCHHMM(bedtime_ref)
});
}
// Session API functions
+14 -14
View File
@@ -28,20 +28,20 @@ const BedtimePlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, wakeup_
return;
}
const data = wakeupBedtime.days.map((day) => {
const daysAgo = Math.floor(
(new Date(getToday()).getTime() - new Date(day.date).getTime()) / (1000 * 60 * 60 * 24)
);
const offsetFromRef = day.bedtime_minutes !== null ? getLocalOffsetFromReference(day.bedtime_minutes, bedtime_ref) : 0;
return {
date: daysAgo === 0 ? 'Today' : `${daysAgo}d ago`,
minutes: offsetFromRef,
time:
day.bedtime_minutes !== null
? formatMinutesAfter(offsetFromRef, bedtime_ref)
: 'N/A',
};
}).reverse();
const data = wakeupBedtime.days.map((day) => {
const daysAgo = Math.floor(
(new Date(getToday()).getTime() - new Date(day.date).getTime()) / (1000 * 60 * 60 * 24)
);
const offsetFromRef = day.bedtime_minutes ?? 0;
return {
date: daysAgo === 0 ? 'Today' : `${daysAgo}d ago`,
minutes: offsetFromRef,
time:
day.bedtime_minutes !== null
? formatMinutesAfter(offsetFromRef, bedtime_ref)
: 'N/A',
};
}).reverse();
setChartData(data);
}, [wakeupBedtime, bedtime_ref]);
+14 -17
View File
@@ -28,25 +28,22 @@ const WakeupPlot: React.FC<WakeupBedtimeProps> = ({ from_date, to_date, wakeup_r
return;
}
const data = wakeupBedtime.days.map((day) => {
const daysAgo = Math.floor(
(new Date(getToday()).getTime() - new Date(day.date).getTime()) / (1000 * 60 * 60 * 24)
);
const data = wakeupBedtime.days.map((day) => {
const daysAgo = Math.floor(
(new Date(getToday()).getTime() - new Date(day.date).getTime()) / (1000 * 60 * 60 * 24)
);
let offsetFromRef = 0;
if (day.wakeup_minutes !== null) {
offsetFromRef = getLocalOffsetFromReference(day.wakeup_minutes, wakeup_ref);
}
const offsetFromRef = day.wakeup_minutes ?? 0;
return {
date: daysAgo === 0 ? 'Today' : `${daysAgo}d ago`,
minutes: offsetFromRef,
time:
day.wakeup_minutes !== null
? formatMinutesAfter(offsetFromRef, wakeup_ref)
: 'N/A',
};
}).reverse();
return {
date: daysAgo === 0 ? 'Today' : `${daysAgo}d ago`,
minutes: offsetFromRef,
time:
day.wakeup_minutes !== null
? formatMinutesAfter(offsetFromRef, wakeup_ref)
: 'N/A',
};
}).reverse();
setChartData(data);
}, [wakeupBedtime, wakeup_ref]);