Files
babymonitor/frontend/src/utils/chartHelpers.js
T
2026-04-26 17:57:05 +02:00

110 lines
3.4 KiB
JavaScript

/**
* Chart data transformation utilities for baby sleep tracker
*/
/**
* Build timetable slots for visualization
* @param slots - raw timetable slots from API
* @returns grouped slots by date
*/
export function buildTimetableSlots(slots) {
return slots.reduce((acc, slot) => {
if (!acc[slot.date]) {
acc[slot.date] = [];
}
acc[slot.date].push(slot);
return acc;
}, {});
}
/**
* Transform wakeup minutes for Recharts LineChart
* @param days - wakeup/bedtime data from API
* @returns array formatted for LineChart
*/
export function computeWakeupMinutes(days, wakeupRef = "04:00") {
return days.map((day) => ({
date: day.date,
minutes: day.wakeup_minutes ?? 0,
time: day.wakeup_minutes !== null
? formatMinutesAfter(day.wakeup_minutes, wakeupRef)
: "N/A",
}));
}
/**
* Transform bedtime minutes for Recharts LineChart
* @param days - wakeup/bedtime data from API
* @returns array formatted for LineChart
*/
export function computeBedtimeMinutes(days, bedtimeRef = "19:00") {
return days.map((day) => ({
date: day.date,
minutes: day.bedtime_minutes ?? 0,
time: day.bedtime_minutes !== null
? formatMinutesAfter(day.bedtime_minutes, bedtimeRef)
: "N/A",
}));
}
/**
* Transform daily summary for Recharts BarChart (vertical layout)
* @param days - daily summary data from API
* @returns array formatted for BarChart
*/
export function computeDailySummaryData(days) {
return days.map((day) => ({
date: day.date,
daySleep: day.day_minutes,
nightSleep: day.night_minutes,
total: day.total_minutes,
}));
}
/**
* Calculate average summary stats from daily data
* @param days - daily summary data from API
* @returns averages for total, day, and night sleep
*/
export function computeAverageStats(days) {
if (!days.length) {
return { avgTotal: 0, avgDay: 0, avgNight: 0, count: 0 };
}
const totals = days.reduce((acc, day) => ({
total: acc.total + day.total_minutes,
day: acc.day + day.day_minutes,
night: acc.night + day.night_minutes,
}), { total: 0, day: 0, night: 0 });
const count = days.length;
return {
avgTotal: Math.round(totals.total / count),
avgDay: Math.round(totals.day / count),
avgNight: Math.round(totals.night / count),
count,
};
}
/**
* Convert minutes after reference to clock time string
* Internal helper - kept for chartHelpers module
*/
function formatMinutesAfter(minutes, reference) {
const [refHours, refMinutes] = reference.split(":").map(Number);
const totalRefMinutes = refHours * 60 + refMinutes;
const targetMinutes = totalRefMinutes + minutes;
const normalizedMinutes = ((targetMinutes % 1440) + 1440) % 1440;
const hours = Math.floor(normalizedMinutes / 60);
const mins = normalizedMinutes % 60;
return `${String(hours).padStart(2, "0")}:${String(mins).padStart(2, "0")}`;
}
/**
* Reverse date order (newest first for charts)
* @param days - array of day data
* @returns reversed array
*/
export function reverseDateOrder(days) {
return [...days].reverse();
}
/**
* Filter days to only include those with data
* @param days - array of day data
* @returns filtered array
*/
export function filterDaysWithData(days) {
return days.filter((day) => (day.total_minutes ?? 0) > 0);
}