mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
Revert "feat(dashboard): send the glucose card in the owner's glucose unit"
This reverts commit 9455b64375.
This commit is contained in:
1 parent
3a99c8cfee
commit
d644db1975
6 files changed
+4
-126
No files matched your search
@@ -71896,10 +71896,8 @@ components:
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: "null"
|
||||
description: "Explicit unit token. When set it wins over `unitKey`. Set on the `sleep` card (`h`, because its value is a
|
||||
per-night total in hours rather than the canonical SLEEP_DURATION minutes) and, since v1.40.0, on the
|
||||
`glucose` card: the record owner's glucose unit (`mg/dL` or `mmol/L`), with `latestValue`, `secondaryValue`
|
||||
and `sparkline` converted to it (mmol/L to one decimal). Null on every other kind."
|
||||
description: Explicit unit token, set only on the `sleep` card (`h`, because its value is a per-night total in hours
|
||||
rather than the canonical SLEEP_DURATION minutes). Null on every other kind.
|
||||
sleepStages:
|
||||
anyOf:
|
||||
- type: object
|
||||
|
||||
@@ -561,32 +561,6 @@ describe("GET /api/dashboard/summary", () => {
|
||||
expect(glucose?.lastSeenAt).toBe(tenDaysAgo.toISOString());
|
||||
});
|
||||
|
||||
it("names the owner's glucose unit on the glucose card", async () => {
|
||||
// Applied after the summary cache: the unit is the record's own choice
|
||||
// and the card's numbers are in it (the conversion is pinned in
|
||||
// `src/lib/dashboard/__tests__/glucose-card.test.ts`).
|
||||
vi.mocked(getSession).mockResolvedValue({
|
||||
...SESSION_OK,
|
||||
user: { ...SESSION_OK.user, glucoseUnit: "mmol/L" },
|
||||
} as never);
|
||||
vi.mocked(prisma.measurement.groupBy).mockResolvedValue([
|
||||
{
|
||||
type: "BLOOD_GLUCOSE",
|
||||
_count: { _all: 4 },
|
||||
_max: { measuredAt: new Date(Date.now() - 10 * 86_400_000) },
|
||||
},
|
||||
] as never);
|
||||
const res = await callGet(makeReq());
|
||||
const body = (await res.json()) as {
|
||||
data: { metrics: Array<{ id: string; unit: string | null }> };
|
||||
};
|
||||
expect(body.data.metrics.find((m) => m.id === "glucose")?.unit).toBe(
|
||||
"mmol/L",
|
||||
);
|
||||
// Every other card keeps its own unit contract.
|
||||
expect(body.data.metrics.find((m) => m.id === "weight")?.unit).toBeNull();
|
||||
});
|
||||
|
||||
it("emits the sleep tile as the night TIME-ASLEEP total in hours, not one stage (v1.11.4)", async () => {
|
||||
// SLEEP_DURATION is stored one row per STAGE per night (minutes). The
|
||||
// tile must SUM the asleep stages of the latest night and convert to
|
||||
|
||||
@@ -75,8 +75,6 @@ import {
|
||||
} from "@/lib/dashboard/summary-reads";
|
||||
import { resolveModuleMap } from "@/lib/modules/gate";
|
||||
import { gateMetricCardsByModules } from "@/lib/dashboard/widget-modules";
|
||||
import { glucoseCardInDisplayUnit } from "@/lib/dashboard/glucose-card";
|
||||
import { resolveGlucoseUnit } from "@/lib/glucose";
|
||||
import {
|
||||
summarizeSleepNights,
|
||||
reconstructSleepNights,
|
||||
@@ -146,9 +144,6 @@ interface MetricCard {
|
||||
* `latestValue` is a per-NIGHT total expressed in HOURS (a float),
|
||||
* not the canonical `SLEEP_DURATION` minutes — see the sleep block
|
||||
* below for why the night total replaced the single-stage value.
|
||||
* v1.40.0 — the `glucose` tile sets it to the owner's glucose unit
|
||||
* (`"mg/dL"` or `"mmol/L"`), with its values converted to match
|
||||
* (`glucoseCardInDisplayUnit`, applied after the cache read).
|
||||
*/
|
||||
unit: string | null;
|
||||
/**
|
||||
@@ -330,10 +325,7 @@ export const GET = apiHandler(async () => {
|
||||
// it off. Filtering the cached body makes the toggle effective on the very
|
||||
// next request.
|
||||
const modules = await resolveModuleMap(user.id);
|
||||
const glucoseUnit = resolveGlucoseUnit(user.glucoseUnit);
|
||||
const metrics = gateMetricCardsByModules(body.metrics, modules).map((card) =>
|
||||
glucoseCardInDisplayUnit(card, glucoseUnit),
|
||||
);
|
||||
const metrics = gateMetricCardsByModules(body.metrics, modules);
|
||||
annotate({
|
||||
meta: {
|
||||
metrics_emitted: metrics.length,
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { glucoseCardInDisplayUnit } from "../glucose-card";
|
||||
|
||||
const card = (over: Record<string, unknown> = {}) => ({
|
||||
kind: "glucose",
|
||||
latestValue: 101 as number | null,
|
||||
secondaryValue: null as number | null,
|
||||
sparkline: [90, 101, 126],
|
||||
unit: null as string | null,
|
||||
unitKey: "dashboard.metric.unit.glucose",
|
||||
...over,
|
||||
});
|
||||
|
||||
describe("glucoseCardInDisplayUnit", () => {
|
||||
it("converts the card to mmol/L and names the unit", () => {
|
||||
expect(glucoseCardInDisplayUnit(card(), "mmol/L")).toMatchObject({
|
||||
latestValue: 5.6,
|
||||
secondaryValue: null,
|
||||
sparkline: [5, 5.6, 7],
|
||||
unit: "mmol/L",
|
||||
unitKey: "dashboard.metric.unit.glucose",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps mg/dL values and names that unit too", () => {
|
||||
expect(glucoseCardInDisplayUnit(card(), "mg/dL")).toMatchObject({
|
||||
latestValue: 101,
|
||||
sparkline: [90, 101, 126],
|
||||
unit: "mg/dL",
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves an empty card empty", () => {
|
||||
expect(
|
||||
glucoseCardInDisplayUnit(
|
||||
card({ latestValue: null, sparkline: [] }),
|
||||
"mmol/L",
|
||||
),
|
||||
).toMatchObject({ latestValue: null, sparkline: [], unit: "mmol/L" });
|
||||
});
|
||||
|
||||
it("passes every other card through untouched", () => {
|
||||
const weight = card({ kind: "weight", latestValue: 80 });
|
||||
expect(glucoseCardInDisplayUnit(weight, "mmol/L")).toBe(weight);
|
||||
});
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
import { convertGlucose, type GlucoseUnit } from "@/lib/glucose";
|
||||
|
||||
/** The fields of a dashboard summary card the glucose unit touches. */
|
||||
interface GlucoseConvertibleCard {
|
||||
kind: string;
|
||||
latestValue: number | null;
|
||||
secondaryValue: number | null;
|
||||
sparkline: number[];
|
||||
unit: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the glucose card in the record owner's display unit.
|
||||
*
|
||||
* Glucose is stored in mg/dL. The summary card used to send that number with
|
||||
* `unit: null` and a `unitKey` that reads "mg/dL", so a reader who chose
|
||||
* mmol/L was shown 101 "mg/dL" on a client that honours the card. The card now
|
||||
* carries its value, its secondary value and its sparkline in the chosen unit
|
||||
* and names that unit in `unit`, the field that wins over `unitKey` (as the
|
||||
* sleep card's `"h"` already does). Every other card passes through untouched.
|
||||
*
|
||||
* Applied after the summary cache is read, so changing the unit takes effect
|
||||
* on the next request rather than after the cache window.
|
||||
*/
|
||||
export function glucoseCardInDisplayUnit<T extends GlucoseConvertibleCard>(
|
||||
card: T,
|
||||
unit: GlucoseUnit,
|
||||
): T {
|
||||
if (card.kind !== "glucose") return card;
|
||||
const show = (value: number | null) =>
|
||||
value === null ? null : convertGlucose(value, unit);
|
||||
return {
|
||||
...card,
|
||||
latestValue: show(card.latestValue),
|
||||
secondaryValue: show(card.secondaryValue),
|
||||
sparkline: card.sparkline.map((value) => convertGlucose(value, unit)),
|
||||
unit,
|
||||
};
|
||||
}
|
||||
@@ -186,7 +186,7 @@ const dashboardMetricCard = z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe(
|
||||
"Explicit unit token. When set it wins over `unitKey`. Set on the `sleep` card (`h`, because its value is a per-night total in hours rather than the canonical SLEEP_DURATION minutes) and, since v1.40.0, on the `glucose` card: the record owner's glucose unit (`mg/dL` or `mmol/L`), with `latestValue`, `secondaryValue` and `sparkline` converted to it (mmol/L to one decimal). Null on every other kind.",
|
||||
"Explicit unit token, set only on the `sleep` card (`h`, because its value is a per-night total in hours rather than the canonical SLEEP_DURATION minutes). Null on every other kind.",
|
||||
),
|
||||
sleepStages: z
|
||||
.record(z.string(), z.number())
|
||||
|
||||
Reference in new issue
Block a user