fix: dose tracking broken for per-intake takenBy and after medication edits (#100)

- Remove broken isDoseFromPreviousSchedule that falsely dismissed all past doses
  after any medication edit (compared dateOnlyMs < updatedAt incorrectly)
- Fix takenBy normalization in AppContext: event.takenBy (string|null) was passed
  through as-is via || operator instead of being properly converted to string[]
- Fix DashboardPage: 5 locations treated dose.takenBy as single string instead of
  iterating the array, causing per-person dose tracking to silently fail
- Extract isDoseDismissed and computeMissedPastDoseIds as pure testable functions
  from AppContext.tsx into utils/schedule.ts
- Update SharedSchedule.tsx to use shared isDoseDismissed from utils
- Add 22 regression tests covering isDoseDismissed, computeMissedPastDoseIds,
  and full dose-tracking-survives-medication-edit workflows
- Add 'fix bugs, don't test around them' rule to copilot instructions
This commit is contained in:
Daniel Volz
2026-02-06 21:55:21 +01:00
committed by GitHub
parent 869b5774fb
commit 01deea1fa0
6 changed files with 659 additions and 135 deletions
+5 -3
View File
@@ -617,7 +617,7 @@ export function DashboardPage() {
<div className="doses-col">
{item.doses.map((dose) => {
// If no takenBy, show single checkbox; otherwise show one per person
const people = dose.takenBy ? [dose.takenBy] : [null];
const people = dose.takenBy.length > 0 ? dose.takenBy : [null];
return (
<div key={dose.id} className="dose-item past">
<span className="dose-time">{dose.timeStr}</span>
@@ -833,7 +833,9 @@ export function DashboardPage() {
(() => {
const totalFutureDoses = futureDays.flatMap((d) =>
d.meds.flatMap((m) =>
m.doses.flatMap((dose) => (dose.takenBy ? [`${dose.id}-${dose.takenBy}`] : [dose.id]))
m.doses.flatMap((dose) =>
dose.takenBy.length > 0 ? dose.takenBy.map((p) => `${dose.id}-${p}`) : [dose.id]
)
)
);
const takenFutureDoses = totalFutureDoses.filter((id) => takenDoses.has(id)).length;
@@ -955,7 +957,7 @@ export function DashboardPage() {
</div>
<div className="doses-col">
{item.doses.map((dose) => {
const people = dose.takenBy ? [dose.takenBy] : [null];
const people = dose.takenBy.length > 0 ? dose.takenBy : [null];
const allTaken = people.every((person) => takenDoses.has(getDoseId(dose.id, person)));
return (
<div key={dose.id} className={`dose-item future ${allTaken ? "all-taken" : ""}`}>