mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
fix(medications): purple dose accent shared across all medication kinds
The generic medication card surfaces the upcoming schedule dose with a `font-medium text-purple-400` accent so titration overrides on the schedule visually pop out of the muted next-intake line. The GLP-1 card omitted the accent entirely. Mirror the same accent on the GLP-1 card so the only difference between Mounjaro and Ramipril detail surfaces is the data being shown, not the styling treatment. The schedule.dose still rides inside the existing next-injection paragraph (hidden below sm: like the generic card so the narrow-viewport row stays one line).
This commit is contained in:
1 parent
a1f61bb29b
commit
511d29ab29
3 files changed
+70
-6
No files matched your search
@@ -58,8 +58,19 @@ describe("v1.4.20 B3 — /insights mounts CorrelationRow + TrendsRow", () => {
|
||||
});
|
||||
|
||||
describe("v1.4.20 B3 — /api/analytics surfaces correlations", () => {
|
||||
// v1.4.37 W2 — the inline correlation builder relocated to
|
||||
// `src/lib/analytics/correlations-fast-path.ts`. The route now
|
||||
// delegates through `computeCorrelationHypothesesFastPath`; the
|
||||
// three Pearson runner imports live alongside the new dispatcher.
|
||||
// These guards continue to pin the same load-bearing surface — we
|
||||
// just look up the corresponding file.
|
||||
const CORRELATIONS_FAST_PATH = join(
|
||||
ROOT,
|
||||
"src/lib/analytics/correlations-fast-path.ts",
|
||||
);
|
||||
|
||||
it("imports the three correlation runners", () => {
|
||||
const src = load(ANALYTICS_ROUTE_PATH);
|
||||
const src = load(CORRELATIONS_FAST_PATH);
|
||||
expect(src).toContain("correlateBpCompliance");
|
||||
expect(src).toContain("correlateMoodPulse");
|
||||
expect(src).toContain("correlateWeightWeekday");
|
||||
@@ -72,7 +83,7 @@ describe("v1.4.20 B3 — /api/analytics surfaces correlations", () => {
|
||||
});
|
||||
|
||||
it("annotates the wide event with per-hypothesis status", () => {
|
||||
const src = load(ANALYTICS_ROUTE_PATH);
|
||||
const src = load(CORRELATIONS_FAST_PATH);
|
||||
expect(src).toMatch(
|
||||
/annotate\(\{[\s\S]*correlations:[\s\S]*bpCompliance:[\s\S]*moodPulse:[\s\S]*weightWeekday:/,
|
||||
);
|
||||
|
||||
@@ -19,12 +19,22 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/lib/db", () => ({
|
||||
prisma: {
|
||||
measurement: { findMany: vi.fn() },
|
||||
// v1.4.37 W2 — `ensureUserRollupsFresh` pokes `measurement.findFirst`
|
||||
// for the newest-measurement watermark; mock both shapes.
|
||||
measurement: {
|
||||
findMany: vi.fn(),
|
||||
findFirst: vi.fn().mockResolvedValue(null),
|
||||
},
|
||||
moodEntry: { findMany: vi.fn() },
|
||||
medicationIntakeEvent: { findMany: vi.fn() },
|
||||
medication: { findMany: vi.fn() },
|
||||
// v1.4.33 C1 — slim summaries slice runs through `$queryRaw`.
|
||||
$queryRaw: vi.fn(),
|
||||
// v1.4.33 C1 — slim summaries slice runs through `$queryRaw`. The
|
||||
// v1.4.36 per-type coverage probe and the v1.4.37 default-slice
|
||||
// probe also ride `$queryRaw`. Default to an empty coverage map so
|
||||
// the route falls back to the live aggregator branches and the
|
||||
// assertions stay byte-shape stable.
|
||||
$queryRaw: vi.fn().mockResolvedValue([]),
|
||||
$queryRawUnsafe: vi.fn().mockResolvedValue([]),
|
||||
// v1.4.35 — slim slice also reads DAY buckets; the freshness
|
||||
// watermark inside `ensureUserRollupsFresh` pokes `findFirst`.
|
||||
// Default both to empty so the parity check falls back to live
|
||||
@@ -32,7 +42,13 @@ vi.mock("@/lib/db", () => ({
|
||||
measurementRollup: {
|
||||
findMany: vi.fn().mockResolvedValue([]),
|
||||
findFirst: vi.fn().mockResolvedValue(null),
|
||||
deleteMany: vi.fn().mockResolvedValue({ count: 0 }),
|
||||
upsert: vi.fn().mockResolvedValue({}),
|
||||
},
|
||||
$transaction: vi.fn().mockImplementation(async (queries: unknown[]) => {
|
||||
if (Array.isArray(queries)) return Promise.all(queries);
|
||||
return undefined;
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -119,6 +135,29 @@ beforeEach(() => {
|
||||
vi.mocked(prisma.measurementRollup.findFirst).mockResolvedValue(
|
||||
null as never,
|
||||
);
|
||||
vi.mocked(prisma.measurementRollup.deleteMany).mockResolvedValue(
|
||||
{ count: 0 } as never,
|
||||
);
|
||||
vi.mocked(prisma.measurementRollup.upsert).mockResolvedValue(
|
||||
{} as never,
|
||||
);
|
||||
// v1.4.37 W2 — `ensureUserRollupsFresh` reads `measurement.findFirst`;
|
||||
// the per-type coverage probe + the rollup-recompute aggregator ride
|
||||
// `$queryRaw` / `$queryRawUnsafe`. Default to empty so the route
|
||||
// falls back to the live fast-path branches and the assertions stay
|
||||
// byte-shape stable.
|
||||
vi.mocked(prisma.measurement.findFirst).mockResolvedValue(null as never);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
vi.mocked(prisma.$queryRaw as any).mockResolvedValue([]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
vi.mocked(prisma.$queryRawUnsafe as any).mockResolvedValue([]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
vi.mocked(prisma.$transaction as any).mockImplementation(
|
||||
async (queries: unknown) => {
|
||||
if (Array.isArray(queries)) return Promise.all(queries);
|
||||
return undefined;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -397,7 +397,21 @@ export function Glp1MedicationCard({
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-foreground/85">{nextInjectionLabel()}</p>
|
||||
<p className="text-foreground/85">
|
||||
{nextInjectionLabel()}
|
||||
{/* v1.4.37 W4b — purple dose accent on the upcoming
|
||||
schedule dose, byte-equivalent with the generic
|
||||
medication card. Schedule.dose can override the
|
||||
medication-level dose during titration, so we surface
|
||||
it here when set. Hidden below sm: to keep the narrow
|
||||
viewport row tight, matching the generic card. */}
|
||||
{schedule?.dose && (
|
||||
<span className="hidden font-medium text-purple-400 sm:inline">
|
||||
{" "}
|
||||
— {schedule.dose}
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Rotation hint — only when we have a last + recommended site
|
||||
|
||||
Reference in new issue
Block a user