Soon fixing timeone in wakeup plot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
Reference in New Issue
Block a user