diff --git a/src/baby_monitor/static/diapers.html b/src/baby_monitor/static/diapers.html
index be13c30..6e7e603 100644
--- a/src/baby_monitor/static/diapers.html
+++ b/src/baby_monitor/static/diapers.html
@@ -365,7 +365,7 @@
-
Diaper Changes Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})
+
Diaper Changes (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})
@@ -627,36 +627,115 @@
);
}
- // Create days based on currentDaysRange (including today)
- for (let i = currentDaysRange - 1; i >= 0; i--) {
- const date = new Date(now);
- date.setDate(date.getDate() - i);
- date.setHours(0, 0, 0, 0);
+ // If 24 hours selected, show 3-hour aggregates
+ if (currentDaysRange === 1) {
+ // Create 8 three-hour buckets
+ for (let i = 7; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 3);
- const dateStr = date.toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- });
- labels.push(dateStr);
+ const startLabel = periodStart.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ const endLabel = periodEnd.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ labels.push(`${startLabel}-${endLabel}`);
- // Count poop and pee diapers for this day
- const nextDay = new Date(date);
- nextDay.setDate(nextDay.getDate() + 1);
+ // Count poop and pee diapers for this 3-hour period
+ const periodChanges = filteredChanges.filter((dc) => {
+ const changeDate = new Date(dc.change_time);
+ return changeDate >= periodStart && changeDate < periodEnd;
+ });
- const dayChanges = filteredChanges.filter((dc) => {
- const changeDate = new Date(dc.change_time);
- return changeDate >= date && changeDate < nextDay;
- });
+ const poopCount = periodChanges.filter(
+ (dc) => dc.poop_amount !== null,
+ ).length;
+ const peeCount = periodChanges.filter(
+ (dc) => dc.pee_amount !== null,
+ ).length;
- const poopCount = dayChanges.filter(
- (dc) => dc.poop_amount !== null,
- ).length;
- const peeCount = dayChanges.filter(
- (dc) => dc.pee_amount !== null,
- ).length;
+ poopData.push(poopCount);
+ peeData.push(peeCount);
+ }
+ } else if (currentDaysRange === 3) {
+ // Show 8-hour aggregates for 3 days (9 buckets total)
+ for (let i = 8; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 8);
- poopData.push(poopCount);
- peeData.push(peeCount);
+ // Format label based on the 8-hour period
+ const dayStr = periodStart.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ const startHour = periodStart.getHours();
+ let periodLabel;
+ if (startHour >= 0 && startHour < 8) {
+ periodLabel = `${dayStr} Night`;
+ } else if (startHour >= 8 && startHour < 16) {
+ periodLabel = `${dayStr} Morning`;
+ } else {
+ periodLabel = `${dayStr} Evening`;
+ }
+ labels.push(periodLabel);
+
+ // Count poop and pee diapers for this 8-hour period
+ const periodChanges = filteredChanges.filter((dc) => {
+ const changeDate = new Date(dc.change_time);
+ return changeDate >= periodStart && changeDate < periodEnd;
+ });
+
+ const poopCount = periodChanges.filter(
+ (dc) => dc.poop_amount !== null,
+ ).length;
+ const peeCount = periodChanges.filter(
+ (dc) => dc.pee_amount !== null,
+ ).length;
+
+ poopData.push(poopCount);
+ peeData.push(peeCount);
+ }
+ } else {
+ // Create days based on currentDaysRange (including today)
+ for (let i = currentDaysRange - 1; i >= 0; i--) {
+ const date = new Date(now);
+ date.setDate(date.getDate() - i);
+ date.setHours(0, 0, 0, 0);
+
+ const dateStr = date.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ labels.push(dateStr);
+
+ // Count poop and pee diapers for this day
+ const nextDay = new Date(date);
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ const dayChanges = filteredChanges.filter((dc) => {
+ const changeDate = new Date(dc.change_time);
+ return changeDate >= date && changeDate < nextDay;
+ });
+
+ const poopCount = dayChanges.filter(
+ (dc) => dc.poop_amount !== null,
+ ).length;
+ const peeCount = dayChanges.filter(
+ (dc) => dc.pee_amount !== null,
+ ).length;
+
+ poopData.push(poopCount);
+ peeData.push(peeCount);
+ }
}
return { labels, poopData, peeData };
@@ -724,7 +803,7 @@
beginAtZero: true,
title: {
display: true,
- text: "Number of Diapers",
+ text: "Number of Changes",
font: {
size: 13,
weight: "600",
diff --git a/src/baby_monitor/static/feedings.html b/src/baby_monitor/static/feedings.html
index 9e38f5e..8da30d5 100644
--- a/src/baby_monitor/static/feedings.html
+++ b/src/baby_monitor/static/feedings.html
@@ -402,7 +402,7 @@
-
Feedings Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})
+
Feedings (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})
@@ -661,28 +661,91 @@
);
}
- // Create days based on currentDaysRange (including today)
- for (let i = currentDaysRange - 1; i >= 0; i--) {
- const date = new Date(now);
- date.setDate(date.getDate() - i);
- date.setHours(0, 0, 0, 0);
+ // If 24 hours selected, show 3-hour aggregates
+ if (currentDaysRange === 1) {
+ // Create 8 three-hour buckets
+ for (let i = 7; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 3);
- const dateStr = date.toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- });
- labels.push(dateStr);
+ const startLabel = periodStart.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ const endLabel = periodEnd.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ labels.push(`${startLabel}-${endLabel}`);
- // Count feedings for this day
- const nextDay = new Date(date);
- nextDay.setDate(nextDay.getDate() + 1);
+ // Count feedings for this 3-hour period
+ const count = filteredFeedings.filter((f) => {
+ const feedingDate = new Date(f.start_time);
+ return feedingDate >= periodStart && feedingDate < periodEnd;
+ }).length;
- const count = filteredFeedings.filter((f) => {
- const feedingDate = new Date(f.start_time);
- return feedingDate >= date && feedingDate < nextDay;
- }).length;
+ data.push(count);
+ }
+ } else if (currentDaysRange === 3) {
+ // Show 8-hour aggregates for 3 days (9 buckets total)
+ for (let i = 8; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 8);
- data.push(count);
+ // Format label based on the 8-hour period
+ const dayStr = periodStart.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ const startHour = periodStart.getHours();
+ let periodLabel;
+ if (startHour >= 0 && startHour < 8) {
+ periodLabel = `${dayStr} Night`;
+ } else if (startHour >= 8 && startHour < 16) {
+ periodLabel = `${dayStr} Morning`;
+ } else {
+ periodLabel = `${dayStr} Evening`;
+ }
+ labels.push(periodLabel);
+
+ // Count feedings for this 8-hour period
+ const count = filteredFeedings.filter((f) => {
+ const feedingDate = new Date(f.start_time);
+ return feedingDate >= periodStart && feedingDate < periodEnd;
+ }).length;
+
+ data.push(count);
+ }
+ } else {
+ // Create days based on currentDaysRange (including today)
+ for (let i = currentDaysRange - 1; i >= 0; i--) {
+ const date = new Date(now);
+ date.setDate(date.getDate() - i);
+ date.setHours(0, 0, 0, 0);
+
+ const dateStr = date.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ labels.push(dateStr);
+
+ // Count feedings for this day
+ const nextDay = new Date(date);
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ const count = filteredFeedings.filter((f) => {
+ const feedingDate = new Date(f.start_time);
+ return feedingDate >= date && feedingDate < nextDay;
+ }).length;
+
+ data.push(count);
+ }
}
return { labels, data };
diff --git a/src/baby_monitor/static/sleep.html b/src/baby_monitor/static/sleep.html
index 10df90c..823b50a 100644
--- a/src/baby_monitor/static/sleep.html
+++ b/src/baby_monitor/static/sleep.html
@@ -536,42 +536,105 @@
return `${hours}h ${mins}m`;
}
- function prepareBarChartData(sleeps, timeRange) {
- const days = {};
- const today = new Date();
- today.setHours(0, 0, 0, 0);
+ function prepareBarChartData(sleepSessions) {
+ const now = new Date();
+ const labels = [];
+ const data = [];
- // Initialize all days in range
- for (let i = timeRange - 1; i >= 0; i--) {
- const date = new Date(today);
- date.setDate(date.getDate() - i);
- const dateStr = date.toISOString().split("T")[0];
- days[dateStr] = 0;
+ // Filter by selected child if applicable
+ let filteredSessions = sleepSessions;
+ if (selectedChildId !== null) {
+ filteredSessions = sleepSessions.filter(
+ (session) => session.child_id === selectedChildId,
+ );
}
- // Count sleeps per day
- sleeps.forEach((sleep) => {
- const date = new Date(sleep.start_time);
- date.setHours(0, 0, 0, 0);
- const dateStr = date.toISOString().split("T")[0];
- if (days.hasOwnProperty(dateStr)) {
- days[dateStr]++;
+ // If 24 hours selected, show 3-hour aggregates
+ if (currentDaysRange === 1) {
+ // Create 8 three-hour buckets
+ for (let i = 7; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 3);
+
+ const startLabel = periodStart.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ const endLabel = periodEnd.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ hour12: true,
+ });
+ labels.push(`${startLabel}-${endLabel}`);
+
+ // Count sleep sessions for this 3-hour period
+ const count = filteredSessions.filter((session) => {
+ const startDate = new Date(session.start_time);
+ return startDate >= periodStart && startDate < periodEnd;
+ }).length;
+
+ data.push(count);
}
- });
+ } else if (currentDaysRange === 3) {
+ // Show 8-hour aggregates for 3 days (9 buckets total)
+ for (let i = 8; i >= 0; i--) {
+ const periodStart = new Date(now);
+ periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
+
+ const periodEnd = new Date(periodStart);
+ periodEnd.setHours(periodEnd.getHours() + 8);
- const labels = Object.keys(days).map((date) => {
- const d = new Date(date);
- return d.toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- });
- });
+ // Format label based on the 8-hour period
+ const dayStr = periodStart.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ const startHour = periodStart.getHours();
+ let periodLabel;
+ if (startHour >= 0 && startHour < 8) {
+ periodLabel = `${dayStr} Night`;
+ } else if (startHour >= 8 && startHour < 16) {
+ periodLabel = `${dayStr} Morning`;
+ } else {
+ periodLabel = `${dayStr} Evening`;
+ }
+ labels.push(periodLabel);
- return {
- labels,
- data: Object.values(days),
- };
- }
+ // Count sleep sessions for this 8-hour period
+ const count = filteredSessions.filter((session) => {
+ const startDate = new Date(session.start_time);
+ return startDate >= periodStart && startDate < periodEnd;
+ }).length;
+
+ data.push(count);
+ }
+ } else {
+ // Create days based on currentDaysRange (including today)
+ for (let i = currentDaysRange - 1; i >= 0; i--) {
+ const date = new Date(now);
+ date.setDate(date.getDate() - i);
+ date.setHours(0, 0, 0, 0);
+
+ const dateStr = date.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ });
+ labels.push(dateStr);
+
+ // Count sleep sessions for this day
+ const nextDay = new Date(date);
+ nextDay.setDate(nextDay.getDate() + 1);
+
+ const count = filteredSessions.filter((session) => {
+ const startDate = new Date(session.start_time);
+ return startDate >= date && startDate < nextDay;
+ }).length;
+
+ data.push(count);
+ }
+ }
function prepareDurationDistributionData(sleeps) {
const ranges = {