mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
Merge remote-tracking branch 'origin/main' into feat/vaccinations-phase-1
This commit is contained in:
commit
4f2dd51390
17 files changed
+146
-39
No files matched your search
@@ -9,9 +9,10 @@ import { SlidersHorizontal, TrendingUp } from "lucide-react";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
// Pure constant — importing it here does NOT pull the dynamically-loaded ECG
|
||||
// component into this bundle, which is exactly why it lives in the lib module.
|
||||
import { ECG_OVERVIEW_LIMIT } from "@/lib/insights/ecg-classification";
|
||||
// Bare number — its own React- and label-map-free module, so importing it here
|
||||
// pulls neither the ECG label map/helpers nor the dynamically-loaded ECG
|
||||
// component into this eager bundle.
|
||||
import { ECG_OVERVIEW_LIMIT } from "@/lib/insights/ecg-overview-limit";
|
||||
import { useFeatureFlags } from "@/hooks/use-feature-flags";
|
||||
import { useInsightsLayoutQuery } from "@/hooks/use-insights-layout";
|
||||
import { usePullToRefresh } from "@/hooks/use-pull-to-refresh";
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
* of the two; `documentDate` is the person's own filing date and is the
|
||||
* fallback.
|
||||
*
|
||||
* Both DTO fields are date-only (`YYYY-MM-DD`), but the suggest endpoint takes
|
||||
* a full instant — the same shape the two lab moments already hand it. So the
|
||||
* date is lifted to noon UTC here, exactly as the OCR review does: the rule is
|
||||
* a ±7-day window, so the time of day never changes the verdict, and noon keeps
|
||||
* a viewer's local midnight from rounding the day either way. Passing the bare
|
||||
* date instead is what made this suggestion silently never appear — the API
|
||||
* answered 422 and the field rendered nothing.
|
||||
*
|
||||
* It renders nothing once the document already names a visit that this session
|
||||
* did not choose: an offer to file something already filed is noise.
|
||||
*/
|
||||
@@ -31,9 +39,10 @@ export function DocumentEncounterSuggestion({
|
||||
onChange: (encounterId: string | null) => void;
|
||||
}) {
|
||||
if (alreadyLinked) return null;
|
||||
const instant = anchor ? `${anchor}T12:00:00.000Z` : null;
|
||||
return (
|
||||
<EncounterSuggestionField
|
||||
anchor={anchor}
|
||||
anchor={instant}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { MetricProvenanceMeta } from "./standards";
|
||||
|
||||
/**
|
||||
* The Health Score's own provenance entry, split out of the full
|
||||
* `METRIC_PROVENANCE` map.
|
||||
*
|
||||
* The eager insights overview reaches this value through
|
||||
* HeroStrip → HealthScoreCard, and it needs only this one metric's method key
|
||||
* and cited standard. Importing the whole map there dragged every derived
|
||||
* metric's citation (~30 entries of DOIs and key strings) into the overview's
|
||||
* initial bundle. Isolating the entry keeps the eager page down to the number
|
||||
* it renders; `METRIC_PROVENANCE.HEALTH_SCORE` re-exports this same value, so
|
||||
* the lazy score surfaces still read one source.
|
||||
*
|
||||
* Cited for the risk-factor set the pillars are drawn from, and for nothing
|
||||
* beyond it. HEARTS names the cardiometabolic factors worth following; it does
|
||||
* not prescribe an equal-weighted average of them, and since v1.35.0 it could
|
||||
* not, because which pillars enter that average is the account's own
|
||||
* selection. Naming the package plainly, as this entry used to, reads as a
|
||||
* standard endorsing whatever recipe the person happens to have chosen, which
|
||||
* is a claim nobody can make. The pillar-level citations in the map are
|
||||
* unaffected: each of those really does describe the band its pillar is graded
|
||||
* against.
|
||||
*/
|
||||
export const HEALTH_SCORE_PROVENANCE: MetricProvenanceMeta = {
|
||||
methodKey: "insights.healthScore.method",
|
||||
standard: {
|
||||
name: "WHO HEARTS technical package (risk-factor set)",
|
||||
url: "https://www.who.int/publications/i/item/9789240001367",
|
||||
},
|
||||
};
|
||||
@@ -23,6 +23,7 @@
|
||||
* covers has to live in `insights.healthScore.method` — the standard entry
|
||||
* alone would say it to nobody.
|
||||
*/
|
||||
import { HEALTH_SCORE_PROVENANCE } from "./health-score-provenance";
|
||||
import type { ProvenanceStandard } from "./provenance-explainer";
|
||||
import type { DerivedMetricId } from "@/lib/insights/derived/registry";
|
||||
|
||||
@@ -198,21 +199,8 @@ export const METRIC_PROVENANCE: Record<DerivedMetricId, MetricProvenanceMeta> =
|
||||
},
|
||||
caveatKey: "insights.derived.composite.SAME_TIME_BASELINE.caveat",
|
||||
},
|
||||
HEALTH_SCORE: {
|
||||
methodKey: "insights.healthScore.method",
|
||||
standard: {
|
||||
// Cited for the risk-factor set the pillars are drawn from, and for
|
||||
// nothing beyond it. HEARTS names the cardiometabolic factors worth
|
||||
// following; it does not prescribe an equal-weighted average of
|
||||
// them, and since v1.35.0 it could not, because which pillars enter
|
||||
// that average is the account's own selection. Naming the package
|
||||
// plainly, as this entry used to, reads as a standard endorsing
|
||||
// whatever recipe the person happens to have chosen, which is a
|
||||
// claim nobody can make. The pillar-level citations elsewhere in
|
||||
// this map are unaffected: each of those really does describe the
|
||||
// band its pillar is graded against.
|
||||
name: "WHO HEARTS technical package (risk-factor set)",
|
||||
url: "https://www.who.int/publications/i/item/9789240001367",
|
||||
},
|
||||
},
|
||||
// The HEALTH_SCORE entry lives in its own module so the eager insights
|
||||
// overview can import just this metric's citation without pulling the whole
|
||||
// map; the rationale for its wording is documented there.
|
||||
HEALTH_SCORE: HEALTH_SCORE_PROVENANCE,
|
||||
};
|
||||
@@ -12,9 +12,9 @@ import { cn } from "@/lib/utils";
|
||||
import { SectionHeading } from "@/components/ui/section-heading";
|
||||
import {
|
||||
ecgResultLabel,
|
||||
ECG_OVERVIEW_LIMIT,
|
||||
type EcgClassification,
|
||||
} from "@/lib/insights/ecg-classification";
|
||||
import { ECG_OVERVIEW_LIMIT } from "@/lib/insights/ecg-overview-limit";
|
||||
import { InsightSectionCard } from "./insight-section-card";
|
||||
|
||||
// Re-exported so the tests (and any teaser call site) can keep importing the
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "@/components/insights/derived/band-tokens";
|
||||
import { CoverageMeter } from "@/components/insights/derived/coverage-meter";
|
||||
import { ProvenanceExplainer } from "@/components/insights/derived/provenance-explainer";
|
||||
import { METRIC_PROVENANCE } from "@/components/insights/derived/standards";
|
||||
import { HEALTH_SCORE_PROVENANCE } from "@/components/insights/derived/health-score-provenance";
|
||||
import {
|
||||
pillarDetailLines,
|
||||
pillarObservedText,
|
||||
@@ -643,8 +643,8 @@ export function HealthScoreCard({
|
||||
)}
|
||||
<ProvenanceExplainer
|
||||
provenance={composite.provenance}
|
||||
method={t(METRIC_PROVENANCE.HEALTH_SCORE.methodKey)}
|
||||
standard={METRIC_PROVENANCE.HEALTH_SCORE.standard}
|
||||
method={t(HEALTH_SCORE_PROVENANCE.methodKey)}
|
||||
standard={HEALTH_SCORE_PROVENANCE.standard}
|
||||
className="block"
|
||||
/>
|
||||
{/* v1.35.0 — the one way into the surface that decides what
|
||||
|
||||
@@ -13,15 +13,6 @@
|
||||
export type EcgClassification =
|
||||
"IRREGULAR" | "NOT_DETECTED" | "INCONCLUSIVE" | null;
|
||||
|
||||
/**
|
||||
* How many strips the OVERVIEW teaser paints. It is a glance, not a history;
|
||||
* the dedicated `/insights/ecg` page passes no limit and shows every
|
||||
* recording. The constant lives here — a pure value with no React import — so
|
||||
* the `/insights` page can pass it without pulling the ECG component eagerly
|
||||
* across its dynamic boundary.
|
||||
*/
|
||||
export const ECG_OVERVIEW_LIMIT = 5;
|
||||
|
||||
/** i18n key per device verdict, under `insights.ecg.result.*`. */
|
||||
export const ECG_RESULT_LABEL_KEYS: Record<string, string> = {
|
||||
IRREGULAR: "insights.ecg.result.irregular",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* How many strips the OVERVIEW teaser paints. It is a glance, not a history;
|
||||
* the dedicated `/insights/ecg` page passes no limit and shows every
|
||||
* recording.
|
||||
*
|
||||
* The value lives in its own React- and label-map-free module so the
|
||||
* `/insights` overview page can pass it without pulling the ECG label map,
|
||||
* its helpers, or the recording component across the dynamic boundary — a
|
||||
* bare number is all the eager page imports.
|
||||
*/
|
||||
export const ECG_OVERVIEW_LIMIT = 5;
|
||||
Reference in new issue
Block a user