@@ -506,7 +510,7 @@
renderBarChart(barChartData);
renderPoopPieChart(poopPieData);
renderPeePieChart(peePieData);
-
+
// Render diaper change list
renderDiaperList(diaperChanges);
}
@@ -526,7 +530,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- filteredChanges = filteredChanges.filter((dc) => dc.child_id === selectedChildId);
+ filteredChanges = filteredChanges.filter(
+ (dc) => dc.child_id === selectedChildId,
+ );
}
// Sort by most recent first
@@ -534,50 +540,62 @@
return new Date(b.change_time) - new Date(a.change_time);
});
- const listHtml = filteredChanges.map((dc) => {
- const changeTime = new Date(dc.change_time);
-
- const dateStr = changeTime.toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- year: "numeric",
- });
-
- const timeStr = changeTime.toLocaleTimeString("en-US", {
- hour: "numeric",
- minute: "2-digit",
- });
+ const listHtml = filteredChanges
+ .map((dc) => {
+ const changeTime = new Date(dc.change_time);
- // Build badges for poop and pee
- let badges = [];
- if (dc.poop_amount || dc.poop_color) {
- const poopInfo = [dc.poop_amount, dc.poop_color].filter(Boolean).join(", ");
- badges.push(`
`);
- }
- if (dc.pee_amount || dc.pee_color) {
- const peeInfo = [dc.pee_amount, dc.pee_color].filter(Boolean).join(", ");
- badges.push(`
`);
- }
- if (badges.length === 0) {
- badges.push('
');
- }
+ const dateStr = changeTime.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ });
- // Get child name
- const child = allChildren.find(c => c.id === dc.child_id);
- const childName = child ? child.name : "Unknown";
+ const timeStr = changeTime.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ minute: "2-digit",
+ });
- return `
+ // Build badges for poop and pee
+ let badges = [];
+ if (dc.poop_amount || dc.poop_color) {
+ const poopInfo = [dc.poop_amount, dc.poop_color]
+ .filter(Boolean)
+ .join(", ");
+ badges.push(
+ `
`,
+ );
+ }
+ if (dc.pee_amount || dc.pee_color) {
+ const peeInfo = [dc.pee_amount, dc.pee_color]
+ .filter(Boolean)
+ .join(", ");
+ badges.push(
+ `
`,
+ );
+ }
+ if (badges.length === 0) {
+ badges.push(
+ '
',
+ );
+ }
+
+ // Get child name
+ const child = allChildren.find((c) => c.id === dc.child_id);
+ const childName = child ? child.name : "Unknown";
+
+ return `
`;
- }).join("");
+ })
+ .join("");
const listContainer = `
@@ -592,7 +610,7 @@
`;
const content = document.getElementById("content");
- content.insertAdjacentHTML('beforeend', listContainer);
+ content.insertAdjacentHTML("beforeend", listContainer);
}
function editDiaperChange(diaperChangeId) {
@@ -617,7 +635,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- recentChanges = recentChanges.filter((dc) => dc.child_id === selectedChildId);
+ recentChanges = recentChanges.filter(
+ (dc) => dc.child_id === selectedChildId,
+ );
}
// Count poop amounts
@@ -670,7 +690,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- recentChanges = recentChanges.filter((dc) => dc.child_id === selectedChildId);
+ recentChanges = recentChanges.filter(
+ (dc) => dc.child_id === selectedChildId,
+ );
}
// Count pee amounts
@@ -718,7 +740,9 @@
// Filter by selected child if applicable
let filteredChanges = diaperChanges;
if (selectedChildId !== null) {
- filteredChanges = diaperChanges.filter((dc) => dc.child_id === selectedChildId);
+ filteredChanges = diaperChanges.filter(
+ (dc) => dc.child_id === selectedChildId,
+ );
}
// Create days based on currentDaysRange (including today)
@@ -742,8 +766,12 @@
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;
+ 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);
@@ -754,7 +782,7 @@
function renderBarChart(chartData) {
const ctx = document.getElementById("diaperChart").getContext("2d");
-
+
new Chart(ctx, {
type: "bar",
data: {
@@ -847,21 +875,33 @@
function renderPoopPieChart(chartData) {
const ctx = document.getElementById("poopPieChart").getContext("2d");
-
+
const colors = {
- "Light": { bg: "rgba(139, 69, 19, 0.5)", border: "rgba(139, 69, 19, 1)" },
- "Medium": { bg: "rgba(139, 69, 19, 0.7)", border: "rgba(139, 69, 19, 1)" },
- "Heavy": { bg: "rgba(139, 69, 19, 0.9)", border: "rgba(139, 69, 19, 1)" },
- "No Poop": { bg: "rgba(200, 200, 200, 0.5)", border: "rgba(200, 200, 200, 1)" },
+ Light: {
+ bg: "rgba(139, 69, 19, 0.5)",
+ border: "rgba(139, 69, 19, 1)",
+ },
+ Medium: {
+ bg: "rgba(139, 69, 19, 0.7)",
+ border: "rgba(139, 69, 19, 1)",
+ },
+ Heavy: {
+ bg: "rgba(139, 69, 19, 0.9)",
+ border: "rgba(139, 69, 19, 1)",
+ },
+ "No Poop": {
+ bg: "rgba(200, 200, 200, 0.5)",
+ border: "rgba(200, 200, 200, 1)",
+ },
};
const backgroundColors = chartData.labels.map(
- (label) => colors[label]?.bg || "rgba(200, 200, 200, 0.5)"
+ (label) => colors[label]?.bg || "rgba(200, 200, 200, 0.5)",
);
const borderColors = chartData.labels.map(
- (label) => colors[label]?.border || "rgba(200, 200, 200, 1)"
+ (label) => colors[label]?.border || "rgba(200, 200, 200, 1)",
);
-
+
new Chart(ctx, {
type: "pie",
data: {
@@ -900,8 +940,12 @@
callbacks: {
label: function (context) {
const count = context.parsed;
- const total = context.dataset.data.reduce((a, b) => a + b, 0);
- const percentage = total > 0 ? ((count / total) * 100).toFixed(1) : 0;
+ const total = context.dataset.data.reduce(
+ (a, b) => a + b,
+ 0,
+ );
+ const percentage =
+ total > 0 ? ((count / total) * 100).toFixed(1) : 0;
return `${context.label}: ${count} (${percentage}%)`;
},
},
@@ -913,21 +957,33 @@
function renderPeePieChart(chartData) {
const ctx = document.getElementById("peePieChart").getContext("2d");
-
+
const colors = {
- "Light": { bg: "rgba(255, 215, 0, 0.5)", border: "rgba(255, 215, 0, 1)" },
- "Medium": { bg: "rgba(255, 215, 0, 0.7)", border: "rgba(255, 215, 0, 1)" },
- "Heavy": { bg: "rgba(255, 215, 0, 0.9)", border: "rgba(255, 215, 0, 1)" },
- "No Pee": { bg: "rgba(200, 200, 200, 0.5)", border: "rgba(200, 200, 200, 1)" },
+ Light: {
+ bg: "rgba(255, 215, 0, 0.5)",
+ border: "rgba(255, 215, 0, 1)",
+ },
+ Medium: {
+ bg: "rgba(255, 215, 0, 0.7)",
+ border: "rgba(255, 215, 0, 1)",
+ },
+ Heavy: {
+ bg: "rgba(255, 215, 0, 0.9)",
+ border: "rgba(255, 215, 0, 1)",
+ },
+ "No Pee": {
+ bg: "rgba(200, 200, 200, 0.5)",
+ border: "rgba(200, 200, 200, 1)",
+ },
};
const backgroundColors = chartData.labels.map(
- (label) => colors[label]?.bg || "rgba(200, 200, 200, 0.5)"
+ (label) => colors[label]?.bg || "rgba(200, 200, 200, 0.5)",
);
const borderColors = chartData.labels.map(
- (label) => colors[label]?.border || "rgba(200, 200, 200, 1)"
+ (label) => colors[label]?.border || "rgba(200, 200, 200, 1)",
);
-
+
new Chart(ctx, {
type: "pie",
data: {
@@ -966,8 +1022,12 @@
callbacks: {
label: function (context) {
const count = context.parsed;
- const total = context.dataset.data.reduce((a, b) => a + b, 0);
- const percentage = total > 0 ? ((count / total) * 100).toFixed(1) : 0;
+ const total = context.dataset.data.reduce(
+ (a, b) => a + b,
+ 0,
+ );
+ const percentage =
+ total > 0 ? ((count / total) * 100).toFixed(1) : 0;
return `${context.label}: ${count} (${percentage}%)`;
},
},
diff --git a/src/baby_monitor/static/feedings.html b/src/baby_monitor/static/feedings.html
index 38375a3..58c8c9b 100644
--- a/src/baby_monitor/static/feedings.html
+++ b/src/baby_monitor/static/feedings.html
@@ -470,7 +470,8 @@
}
function onChildChange(event) {
- selectedChildId = event.target.value === "all" ? null : parseInt(event.target.value);
+ selectedChildId =
+ event.target.value === "all" ? null : parseInt(event.target.value);
displayFeedings(allFeedings);
}
@@ -492,31 +493,34 @@
const durationChartData = prepareDurationChartData(feedings);
// Build child dropdown options
- const childOptions = allChildren.map(child =>
- `
`
- ).join('');
+ const childOptions = allChildren
+ .map(
+ (child) =>
+ `
`,
+ )
+ .join("");
content.innerHTML = `
-
Feedings Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? 's' : ''})
+
Feedings Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})
@@ -543,7 +547,7 @@
renderBarChart(barChartData);
renderPieChart(pieChartData);
renderDurationChart(durationChartData);
-
+
// Render feeding list
renderFeedingList(feedings);
}
@@ -563,7 +567,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- filteredFeedings = filteredFeedings.filter((f) => f.child_id === selectedChildId);
+ filteredFeedings = filteredFeedings.filter(
+ (f) => f.child_id === selectedChildId,
+ );
}
// Sort by most recent first
@@ -571,45 +577,49 @@
return new Date(b.start_time) - new Date(a.start_time);
});
- const listHtml = filteredFeedings.map((feeding) => {
- const startTime = new Date(feeding.start_time);
- const endTime = feeding.end_time ? new Date(feeding.end_time) : null;
-
- const dateStr = startTime.toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- year: "numeric",
- });
-
- const timeStr = startTime.toLocaleTimeString("en-US", {
- hour: "numeric",
- minute: "2-digit",
- });
+ const listHtml = filteredFeedings
+ .map((feeding) => {
+ const startTime = new Date(feeding.start_time);
+ const endTime = feeding.end_time
+ ? new Date(feeding.end_time)
+ : null;
- const duration = endTime
- ? Math.round((endTime - startTime) / 60000)
- : null;
+ const dateStr = startTime.toLocaleDateString("en-US", {
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ });
- const typeClass = feeding.feeding_type.replace("_", "-");
- const typeLabel = formatFeedingType(feeding.feeding_type);
+ const timeStr = startTime.toLocaleTimeString("en-US", {
+ hour: "numeric",
+ minute: "2-digit",
+ });
- // Get child name
- const child = allChildren.find(c => c.id === feeding.child_id);
- const childName = child ? child.name : "Unknown";
+ const duration = endTime
+ ? Math.round((endTime - startTime) / 60000)
+ : null;
- return `
+ const typeClass = feeding.feeding_type.replace("_", "-");
+ const typeLabel = formatFeedingType(feeding.feeding_type);
+
+ // Get child name
+ const child = allChildren.find((c) => c.id === feeding.child_id);
+ const childName = child ? child.name : "Unknown";
+
+ return `
-
${dateStr} at ${timeStr}${selectedChildId === null ? ` - ${childName}` : ''}
+
${dateStr} at ${timeStr}${selectedChildId === null ? ` - ${childName}` : ""}
${typeLabel}
- ${duration !== null ? `${duration} minutes` : 'Ongoing'}
+ ${duration !== null ? `${duration} minutes` : "Ongoing"}
`;
- }).join("");
+ })
+ .join("");
const listContainer = `
@@ -624,7 +634,7 @@
`;
const content = document.getElementById("content");
- content.insertAdjacentHTML('beforeend', listContainer);
+ content.insertAdjacentHTML("beforeend", listContainer);
}
function formatFeedingType(type) {
@@ -660,7 +670,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- recentFeedings = recentFeedings.filter((f) => f.child_id === selectedChildId);
+ recentFeedings = recentFeedings.filter(
+ (f) => f.child_id === selectedChildId,
+ );
}
const typeCounts = {
@@ -708,7 +720,9 @@
// Filter by selected child if applicable
if (selectedChildId !== null) {
- completedFeedings = completedFeedings.filter((f) => f.child_id === selectedChildId);
+ completedFeedings = completedFeedings.filter(
+ (f) => f.child_id === selectedChildId,
+ );
}
// Calculate durations in minutes
@@ -721,14 +735,14 @@
// Find max duration to determine how many bins we need
const maxDuration = Math.max(...durations, 0);
const maxBin = Math.ceil(maxDuration / 5) * 5; // Round up to nearest 5
-
+
// Create 5-minute duration buckets dynamically
const buckets = {};
for (let i = 0; i < maxBin; i += 5) {
const label = `${i}-${i + 5}`;
buckets[label] = 0;
}
-
+
// Add a final bucket for anything over the max
if (maxBin > 0) {
buckets[`${maxBin}+`] = 0;
@@ -738,7 +752,7 @@
durations.forEach((duration) => {
const binIndex = Math.floor(duration / 5) * 5;
const label = `${binIndex}-${binIndex + 5}`;
-
+
if (buckets[label] !== undefined) {
buckets[label]++;
} else {
@@ -760,7 +774,9 @@
// Filter by selected child if applicable
let filteredFeedings = feedings;
if (selectedChildId !== null) {
- filteredFeedings = feedings.filter((f) => f.child_id === selectedChildId);
+ filteredFeedings = feedings.filter(
+ (f) => f.child_id === selectedChildId,
+ );
}
// Create days based on currentDaysRange (including today)
@@ -792,7 +808,7 @@
function renderBarChart(chartData) {
const ctx = document.getElementById("feedingsChart").getContext("2d");
-
+
new Chart(ctx, {
type: "bar",
data: {
@@ -870,7 +886,7 @@
function renderPieChart(chartData) {
const ctx = document.getElementById("pieChart").getContext("2d");
-
+
// Color mapping for each type
const colorMap = {
"Left Breast": {
@@ -881,7 +897,7 @@
background: "rgba(118, 75, 162, 0.8)",
border: "rgba(118, 75, 162, 1)",
},
- "Bottle": {
+ Bottle: {
background: "rgba(255, 159, 64, 0.8)",
border: "rgba(255, 159, 64, 1)",
},
@@ -889,12 +905,12 @@
// Generate colors based on labels present
const backgroundColors = chartData.labels.map(
- (label) => colorMap[label]?.background || "rgba(200, 200, 200, 0.8)"
+ (label) => colorMap[label]?.background || "rgba(200, 200, 200, 0.8)",
);
const borderColors = chartData.labels.map(
- (label) => colorMap[label]?.border || "rgba(200, 200, 200, 1)"
+ (label) => colorMap[label]?.border || "rgba(200, 200, 200, 1)",
);
-
+
new Chart(ctx, {
type: "pie",
data: {
@@ -933,8 +949,12 @@
callbacks: {
label: function (context) {
const count = context.parsed;
- const total = context.dataset.data.reduce((a, b) => a + b, 0);
- const percentage = total > 0 ? ((count / total) * 100).toFixed(1) : 0;
+ const total = context.dataset.data.reduce(
+ (a, b) => a + b,
+ 0,
+ );
+ const percentage =
+ total > 0 ? ((count / total) * 100).toFixed(1) : 0;
return `${context.label}: ${count} (${percentage}%)`;
},
},
@@ -946,7 +966,7 @@
function renderDurationChart(chartData) {
const ctx = document.getElementById("durationChart").getContext("2d");
-
+
new Chart(ctx, {
type: "bar",
data: {
diff --git a/src/baby_monitor/static/log-diaper.html b/src/baby_monitor/static/log-diaper.html
index 94f2978..50cf19a 100644
--- a/src/baby_monitor/static/log-diaper.html
+++ b/src/baby_monitor/static/log-diaper.html
@@ -232,7 +232,11 @@
-