mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(insights): keep a medication course in the storyline through its last day
endsOn is a calendar date, and the storyline compared it with the instant now, so a course dropped out on its final day. Compare it with the user's own today as the column's date value instead.
This commit is contained in:
1 parent
67d88de3d5
commit
9662a3d104
3 files changed
+35
-2
No files matched your search
@@ -194,3 +194,20 @@ describe("adherence storyline ↔ dashboard-tile engine parity", () => {
|
||||
expect(story).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("adherence storyline course window", () => {
|
||||
it("keeps a course on its last day in the user's zone", async () => {
|
||||
// 2026-06-21 20:00 in Los Angeles, already the 22nd in UTC. A course
|
||||
// whose `endsOn` (a calendar date) is the 21st is still running.
|
||||
const now = new Date("2026-06-22T03:00:00.000Z");
|
||||
await buildAdherenceStoryline("user-1", "America/Los_Angeles", now);
|
||||
const where = mocks.medicationFindMany.mock.calls[0]![0].where as {
|
||||
OR: [unknown, { endsOn: { gte: Date } }];
|
||||
};
|
||||
const lastDay = new Date("2026-06-21T00:00:00.000Z"); // @db.Date value
|
||||
expect(where.OR[1].endsOn.gte.getTime()).toBeLessThanOrEqual(
|
||||
lastDay.getTime(),
|
||||
);
|
||||
expect(where.OR[1].endsOn.gte.toISOString()).toBe(lastDay.toISOString());
|
||||
});
|
||||
});
|
||||
@@ -28,6 +28,7 @@ import { probeRollupCoverage } from "@/lib/rollups/measurement-coverage";
|
||||
import { readDayMeanSeries } from "@/lib/insights/derived/baseline";
|
||||
import { buildScheduleAnchoredComplianceBuckets } from "@/lib/analytics/schedule-anchored-compliance";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/resolver";
|
||||
import { userDayKey } from "@/lib/tz/format";
|
||||
import { sanitizeForPrompt } from "@/lib/insights/sanitize";
|
||||
import {
|
||||
inferMedTargetClass,
|
||||
@@ -35,6 +36,7 @@ import {
|
||||
type MedTargetClass,
|
||||
} from "@/lib/medications/med-target-map";
|
||||
import { TRACKED_INTAKE_WHERE } from "@/lib/medications/intake-tracking";
|
||||
import { dbDate } from "@/lib/tz/date-only";
|
||||
|
||||
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
||||
const MAD_TO_SIGMA = 1.4826;
|
||||
@@ -160,7 +162,11 @@ export async function buildAdherenceStoryline(
|
||||
timezone: string | null,
|
||||
now: Date = new Date(),
|
||||
): Promise<AdherenceStoryline | null> {
|
||||
// 1. Active medications with a confidently-known target class.
|
||||
// 1. Active medications with a confidently-known target class. `endsOn` is
|
||||
// a calendar date, so a course is over only once the user's own day has
|
||||
// passed it; comparing the column against the instant `now` dropped the
|
||||
// course's last day.
|
||||
const todayKey = userDayKey(now, timezone ?? DEFAULT_TIMEZONE);
|
||||
const meds = await prisma.medication.findMany({
|
||||
where: {
|
||||
userId,
|
||||
@@ -168,7 +174,7 @@ export async function buildAdherenceStoryline(
|
||||
// v1.39.1 (#1033) — the adherence figure below counts tracked
|
||||
// medications only, so a record-only one cannot be its subject.
|
||||
...TRACKED_INTAKE_WHERE,
|
||||
OR: [{ endsOn: null }, { endsOn: { gte: now } }],
|
||||
OR: [{ endsOn: null }, { endsOn: { gte: dbDate(todayKey) } }],
|
||||
},
|
||||
select: { name: true, treatmentClass: true },
|
||||
});
|
||||
|
||||
@@ -34,3 +34,13 @@ export function dateOnlyAtNoonUtc(key: string): Date {
|
||||
export function dateOnlyKey(value: Date): string {
|
||||
return value.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value a `@db.Date` column holds for calendar date `key` (Prisma reads
|
||||
* and writes those columns as UTC midnight). Use it to compare such a column
|
||||
* with a day: `endsOn >= dbDate(todayKey)` keeps a course through its last
|
||||
* day, where comparing against the instant `now` dropped that day.
|
||||
*/
|
||||
export function dbDate(key: string): Date {
|
||||
return new Date(`${key}T00:00:00.000Z`);
|
||||
}
|
||||
Reference in new issue
Block a user