mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
feat(measurements): log a resting heart rate by hand
The entry form offered pulse but not resting heart rate, which has its own chart and series, so a value read off a watch or taken on waking could only land among spot pulses. The form now offers it next to pulse. The server already gates the type on the recovery module (its resting_hr domain), so the form, the dashboard summary, the resting-pulse page, its trend slot and its correlation channel now follow that module too. Refs #1079
This commit is contained in:
1 parent
82ccac2fd0
commit
08d5acdcb5
3 files changed
+61
No files matched your search
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* The manual-entry form offers the resting heart rate (#1079).
|
||||
*
|
||||
* Resting heart rate has its own chart and series, separate from spot pulse.
|
||||
* A value read off a watch or taken on waking had no row in the form, so it
|
||||
* could only be logged as a pulse, which feeds a different chart.
|
||||
*/
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { VALUE_RANGES, getUnitForType } from "@/lib/validations/measurement";
|
||||
import {
|
||||
MEASUREMENT_FORM_TYPE_VALUES,
|
||||
MEASUREMENT_TYPES,
|
||||
} from "@/components/measurements/measurement-form";
|
||||
import en from "../../../../messages/en.json";
|
||||
|
||||
describe("manual entry of the resting heart rate", () => {
|
||||
it("offers it as its own type, next to pulse", () => {
|
||||
expect(MEASUREMENT_FORM_TYPE_VALUES).toContain("RESTING_HEART_RATE");
|
||||
const values = MEASUREMENT_TYPES.map((t) => t.value);
|
||||
expect(values.indexOf("RESTING_HEART_RATE")).toBe(
|
||||
values.indexOf("PULSE") + 1,
|
||||
);
|
||||
});
|
||||
|
||||
it("uses the server's unit, a labelled row and a plausible placeholder", () => {
|
||||
const row = MEASUREMENT_TYPES.find((t) => t.value === "RESTING_HEART_RATE");
|
||||
expect(row).toBeDefined();
|
||||
expect(row && "unit" in row ? row.unit : undefined).toBe(
|
||||
getUnitForType("RESTING_HEART_RATE"),
|
||||
);
|
||||
expect(
|
||||
(en as { measurements: Record<string, string> }).measurements
|
||||
.typeRestingHeartRate,
|
||||
).toBeTruthy();
|
||||
const range = VALUE_RANGES.RESTING_HEART_RATE;
|
||||
const placeholder = Number(
|
||||
row && "placeholder" in row ? row.placeholder : NaN,
|
||||
);
|
||||
if (range) {
|
||||
expect(placeholder).toBeGreaterThanOrEqual(range.min);
|
||||
expect(placeholder).toBeLessThanOrEqual(range.max);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -67,6 +67,14 @@ export const MEASUREMENT_TYPES = [
|
||||
unit: "bpm",
|
||||
placeholder: "72",
|
||||
},
|
||||
// The resting heart rate has its own chart and series; a value read off a
|
||||
// watch or taken on waking belongs there rather than among spot pulses.
|
||||
{
|
||||
value: "RESTING_HEART_RATE",
|
||||
labelKey: "measurements.typeRestingHeartRate",
|
||||
unit: "bpm",
|
||||
placeholder: "58",
|
||||
},
|
||||
{
|
||||
value: "BODY_FAT",
|
||||
labelKey: "measurements.typeBodyFat",
|
||||
|
||||
@@ -100,6 +100,9 @@ const STATIC_SURFACE_MODULE = {
|
||||
"insights-page:six-minute-walk": "recovery",
|
||||
"insights-page:stair-ascent-speed": "recovery",
|
||||
"insights-page:stair-descent-speed": "recovery",
|
||||
// The resting heart rate is the recovery module's `resting_hr` domain; its
|
||||
// page, trend slot, correlation channel and summary key follow it.
|
||||
"insights-page:resting-pulse": "recovery",
|
||||
|
||||
// ── Insights overview blocks ──
|
||||
"overview:cycle-summary": "cycle",
|
||||
@@ -115,6 +118,7 @@ const STATIC_SURFACE_MODULE = {
|
||||
// ── Trends row ──
|
||||
"trend:mood": "mood",
|
||||
"trend:sleep": "sleep",
|
||||
"trend:resting_hr": "recovery",
|
||||
|
||||
// ── Add menu ──
|
||||
"capture:mood": "mood",
|
||||
@@ -141,6 +145,9 @@ const STATIC_SURFACE_MODULE = {
|
||||
"summary:SLEEP_DURATION": "sleep",
|
||||
"summary:BLOOD_GLUCOSE": "glucose",
|
||||
"summary:CARDIO_RECOVERY": "recovery",
|
||||
// The recovery module owns the resting_hr domain (`measurement-scope.ts`),
|
||||
// so the server gates the type on it; the form and the dashboard follow.
|
||||
"summary:RESTING_HEART_RATE": "recovery",
|
||||
"summary:SIX_MINUTE_WALK_DISTANCE": "recovery",
|
||||
"summary:STAIR_ASCENT_SPEED": "recovery",
|
||||
"summary:STAIR_DESCENT_SPEED": "recovery",
|
||||
@@ -189,6 +196,7 @@ const STATIC_SURFACE_MODULE = {
|
||||
"correlation:MOOD": "mood",
|
||||
"correlation:SLEEP_DURATION": "sleep",
|
||||
"correlation:BLOOD_GLUCOSE": "glucose",
|
||||
"correlation:RESTING_HEART_RATE": "recovery",
|
||||
"correlation:MEDICATION_COMPLIANCE": "medications",
|
||||
// Symptom burden is read from the illness journal.
|
||||
"correlation:SYMPTOM_SEVERITY": "illness",
|
||||
|
||||
Reference in new issue
Block a user