From 263033adfdbfc75cbd30a6ec155f047b9f915e0e Mon Sep 17 00:00:00 2001 From: Daniel Volz Date: Mon, 29 Dec 2025 22:28:18 +0100 Subject: [PATCH] feat: implement dose tracking cleanup on medication start date change --- backend/src/routes/medications.ts | 31 +++++++++++++++++++++++++++++-- frontend/src/App.tsx | 9 +++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/backend/src/routes/medications.ts b/backend/src/routes/medications.ts index bf18751..7aa2a41 100644 --- a/backend/src/routes/medications.ts +++ b/backend/src/routes/medications.ts @@ -1,8 +1,8 @@ import { FastifyInstance } from "fastify"; import { z } from "zod"; import { db } from "../db/client.js"; -import { medications } from "../db/schema.js"; -import { eq, and } from "drizzle-orm"; +import { medications, doseTracking } from "../db/schema.js"; +import { eq, and, like, sql } from "drizzle-orm"; import { createWriteStream, existsSync, unlinkSync } from "fs"; import { resolve, extname } from "path"; import { pipeline } from "stream/promises"; @@ -199,6 +199,33 @@ export async function medicationRoutes(app: FastifyInstance) { if (!result.length) return reply.notFound(); + // Clean up dose tracking entries that are before the earliest start date + // This ensures consistency when the user changes the start date + const earliestStart = Math.min(...blisters.map(b => new Date(b.start).getTime())); + if (!Number.isNaN(earliestStart)) { + // Get all dose tracking entries for this medication and filter out invalid ones + const allDoses = await db.select().from(doseTracking) + .where(and( + eq(doseTracking.userId, userId), + like(doseTracking.doseId, `${idNum}-%`) + )); + + // Find doses with timestamps before the earliest start date + const dosesToDelete = allDoses.filter(dose => { + const parts = dose.doseId.split("-"); + if (parts.length >= 3) { + const timestamp = parseInt(parts[2], 10); + return !Number.isNaN(timestamp) && timestamp < earliestStart; + } + return false; + }); + + // Delete invalid doses + for (const dose of dosesToDelete) { + await db.delete(doseTracking).where(eq(doseTracking.id, dose.id)); + } + } + return { id: result[0].id, name: result[0].name, diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1846346..6eadfb0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3158,9 +3158,14 @@ function calculateCoverage( if (parts.length >= 3) { const medId = parseInt(parts[0], 10); const blisterIdx = parseInt(parts[1], 10); + const doseTimestamp = parseInt(parts[2], 10); if (medId === m.id && m.blisters[blisterIdx]) { - // Each taken dose (regardless of person) consumes the usage amount - consumed += m.blisters[blisterIdx].usage; + // Only count doses that are on or after the blister's start date + const blisterStart = new Date(m.blisters[blisterIdx].start).getTime(); + if (!Number.isNaN(blisterStart) && doseTimestamp >= blisterStart) { + // Each taken dose (regardless of person) consumes the usage amount + consumed += m.blisters[blisterIdx].usage; + } } } });