fix(day): run only records with a start of their own through a day

The "Running that day" list carried the profile facts (smoking status,
alcohol pattern, shift schedule) as running items, titled by their raw
codes and counted "day n" from the date the fact was filed. A person who
quit smoking years ago and entered it last week read "day 13". Those facts
describe the person, hold no start the person gave, and are not part of a
day; the lifestyle section and its running kind are gone from the day, its
index and the model-facing get_day.

The same false count reached a medication filed without a start date: its
creation date stood in as the start. `since` is now null there, with no
day count, and the entry's date only bounds which days show it. A life
event's category is worded in the reader's language instead of its code.
This commit is contained in:
Marc-André Bombeck committed 2026-10-09 08:38:01 +02:00
1 parent 88836452eb
commit 09f94d3eac
13 files changed
+211 -83

No files matched your search

@@ -190,6 +190,48 @@ describe("<DayView>", () => {
expect(html).toContain('href="/illness/ep1"');
});
it("states no day count for a record without a start, and words a life event's category", async () => {
dayQuery = {
data: {
...DAY,
running: [
{
kind: "medication",
section: "medications",
id: "m9",
title: "Levothyroxine",
sub: "50 µg",
since: null,
until: null,
dayIndex: null,
dayCount: null,
href: "/medications/m9",
},
{
kind: "lifeEvent",
section: "lifeEvents",
id: "le1",
title: "Parental leave",
sub: "FAMILY",
since: "2025-12-01",
until: "2026-02-28",
dayIndex: 34,
dayCount: 90,
href: null,
},
],
},
};
const html = await render();
const rows = html.split('data-slot="day-running-item"').slice(1);
const med = rows.find((row) => row.includes("Levothyroxine")) ?? "";
expect(med).toContain("50 µg");
expect(med.split("</li>")[0]).not.toMatch(/Day \d|since/);
const leave = rows.find((row) => row.includes("Parental leave")) ?? "";
expect(leave).toContain("Family · Day 34 of 90");
expect(leave).not.toContain("FAMILY");
});
it("folds the blood pressure into one tile on its number line", async () => {
const html = await render();
expect(html).toContain('data-type="BLOOD_PRESSURE"');
+18 -10
View File
@@ -23,13 +23,14 @@ import {
type LucideIcon,
} from "lucide-react";
import type {
DayEvent,
DayEventKind,
DayNotable,
DayRunningItem,
DayRunningKind,
DayValue,
import {
LIFE_EVENT_CATEGORIES,
type DayEvent,
type DayEventKind,
type DayNotable,
type DayRunningItem,
type DayRunningKind,
type DayValue,
} from "@/lib/day/contract";
import { useFormatters, useTranslations } from "@/lib/i18n/context";
import { cn } from "@/lib/utils";
@@ -157,7 +158,6 @@ const RUNNING_COLOR: Record<DayRunningKind, string> = {
restMode: "var(--chart-5)",
cyclePhase: "var(--chart-3)",
travel: "var(--chart-4)",
lifestyle: "var(--muted-foreground)",
lifeEvent: "var(--chart-2)",
};
@@ -181,6 +181,10 @@ export function dayTitle(
const FLOW_LEVELS = new Set(["NONE", "SPOTTING", "LIGHT", "MEDIUM", "HEAVY"]);
const LIFE_EVENT_CATEGORY_SET: ReadonlySet<string> = new Set(
LIFE_EVENT_CATEGORIES,
);
function dayMeta(
kind: string,
meta: string,
@@ -189,6 +193,10 @@ function dayMeta(
if (kind === "cycleDayLog" && FLOW_LEVELS.has(meta)) {
return `${t("cycle.flow.label")}: ${t(`cycle.flow.${meta}`)}`;
}
// A life event's second line is its category, a closed code.
if (kind === "lifeEvent" && LIFE_EVENT_CATEGORY_SET.has(meta)) {
return t(`lifeEvents.category.${meta}`);
}
return meta;
}
@@ -202,13 +210,13 @@ export function DayRunning({ items }: { items: readonly DayRunningItem[] }) {
<ul>
{items.map((item) => {
const parts = [
item.sub,
item.sub === null ? null : dayMeta(item.kind, item.sub, t),
item.dayIndex !== null
? item.dayCount !== null
? t("day.dayOf", { n: item.dayIndex, m: item.dayCount })
: t("day.dayN", { n: item.dayIndex })
: null,
item.dayCount === null
item.dayCount === null && item.since !== null
? t("day.since", {
date: fmt.dateShortSmartCalendar(item.since),
})