From dea3b5d3b5f15bb699c319bd293bfe0395402391 Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Tue, 11 Nov 2025 14:29:43 +0100 Subject: [PATCH] persisted selection of child and time range when switching between pages. Also added automatic total sleep time scaling on vertical axis --- src/baby_monitor/static/diapers.html | 10 +++++- src/baby_monitor/static/feedings.html | 10 +++++- src/baby_monitor/static/sleep.html | 46 ++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/baby_monitor/static/diapers.html b/src/baby_monitor/static/diapers.html index 6e7e603..3398923 100644 --- a/src/baby_monitor/static/diapers.html +++ b/src/baby_monitor/static/diapers.html @@ -267,9 +267,15 @@ let allDiaperChanges = []; let allChildren = []; - let currentDaysRange = 7; + let currentDaysRange = parseInt(localStorage.getItem("lastDiaperTimeRange")) || 7; let selectedChildId = null; // null means "All Children" + // Restore last selected child from localStorage + const lastChildId = localStorage.getItem("lastDiaperChildFilter"); + if (lastChildId && lastChildId !== "all") { + selectedChildId = parseInt(lastChildId); + } + // Load diaper changes data async function loadDiaperChanges() { try { @@ -311,12 +317,14 @@ function onDaysRangeChange(event) { currentDaysRange = parseInt(event.target.value); + localStorage.setItem("lastDiaperTimeRange", currentDaysRange); displayDiaperChanges(allDiaperChanges); } function onChildChange(event) { selectedChildId = event.target.value === "all" ? null : parseInt(event.target.value); + localStorage.setItem("lastDiaperChildFilter", event.target.value); displayDiaperChanges(allDiaperChanges); } diff --git a/src/baby_monitor/static/feedings.html b/src/baby_monitor/static/feedings.html index 8da30d5..0337744 100644 --- a/src/baby_monitor/static/feedings.html +++ b/src/baby_monitor/static/feedings.html @@ -304,9 +304,15 @@ let allFeedings = []; let allChildren = []; - let currentDaysRange = 7; + let currentDaysRange = parseInt(localStorage.getItem("lastFeedingTimeRange")) || 7; let selectedChildId = null; // null means "All Children" + // Restore last selected child from localStorage + const lastChildId = localStorage.getItem("lastFeedingChildFilter"); + if (lastChildId && lastChildId !== "all") { + selectedChildId = parseInt(lastChildId); + } + // Load feedings data async function loadFeedings() { try { @@ -348,12 +354,14 @@ function onDaysRangeChange(event) { currentDaysRange = parseInt(event.target.value); + localStorage.setItem("lastFeedingTimeRange", currentDaysRange); displayFeedings(allFeedings); } function onChildChange(event) { selectedChildId = event.target.value === "all" ? null : parseInt(event.target.value); + localStorage.setItem("lastFeedingChildFilter", event.target.value); displayFeedings(allFeedings); } diff --git a/src/baby_monitor/static/sleep.html b/src/baby_monitor/static/sleep.html index 7839437..3210345 100644 --- a/src/baby_monitor/static/sleep.html +++ b/src/baby_monitor/static/sleep.html @@ -339,6 +339,8 @@ document .getElementById("timeRangeFilter") .addEventListener("change", function () { + // Save selection to localStorage + localStorage.setItem("lastSleepTimeRange", this.value); loadData(); }); @@ -374,6 +376,13 @@ selectedChildId = lastChildId; } + // Restore last selected time range from localStorage + const timeRangeFilter = document.getElementById("timeRangeFilter"); + const lastTimeRange = localStorage.getItem("lastSleepTimeRange"); + if (lastTimeRange) { + timeRangeFilter.value = lastTimeRange; + } + // Fetch sleep logs const sleepResponse = await fetch("/api/sleep", { headers: { @@ -778,11 +787,27 @@ console.log('Datasets:', datasets); + // Determine the maximum total duration across all periods (in hours) + const maxDuration = Math.max(...chartData.durations.map(periodDurations => + periodDurations.reduce((sum, val) => sum + val, 0) + ), 0); + + console.log('Max duration (hours):', maxDuration); + + // Decide whether to use minutes or hours based on max duration + const useMinutes = maxDuration < 2; // Use minutes if max is less than 2 hours + + // Convert data to minutes if needed + const finalDatasets = useMinutes ? datasets.map(dataset => ({ + ...dataset, + data: dataset.data.map(hours => hours * 60) // Convert hours to minutes + })) : datasets; + barChartInstance = new Chart(ctx, { type: "bar", data: { labels: chartData.labels, - datasets: datasets, + datasets: finalDatasets, }, options: { responsive: true, @@ -796,11 +821,15 @@ beginAtZero: true, title: { display: true, - text: "Hours", + text: useMinutes ? "Minutes" : "Hours", }, ticks: { callback: function(value) { - return value.toFixed(1) + 'h'; + if (useMinutes) { + return Math.round(value) + 'm'; + } else { + return value.toFixed(1) + 'h'; + } } }, }, @@ -812,8 +841,12 @@ tooltip: { callbacks: { label: function(context) { - const hours = Math.floor(context.parsed.y); - const minutes = Math.round((context.parsed.y - hours) * 60); + const value = useMinutes ? context.parsed.y / 60 : context.parsed.y; + const hours = Math.floor(value); + const minutes = Math.round((value - hours) * 60); + if (hours === 0) { + return `${context.dataset.label}: ${minutes}m`; + } return `${context.dataset.label}: ${hours}h ${minutes}m`; }, footer: function(tooltipItems) { @@ -822,6 +855,9 @@ const hours = Math.floor(totalHours); const minutes = Math.round((totalHours - hours) * 60); const sessionCount = chartData.sessionCounts[periodIndex]; + if (hours === 0) { + return `Total: ${minutes}m (${sessionCount} session${sessionCount !== 1 ? 's' : ''})`; + } return `Total: ${hours}h ${minutes}m (${sessionCount} session${sessionCount !== 1 ? 's' : ''})`; } }