feat(web): questionnaires, diary and medication module in the patient app
- Focus screen renders versioned questionnaire items (iq: buttons): section chip, position (adaptive forms without "of N"), recall date, pause / help-now actions, optional skip, sleep-hours input, 0-10 scale anchors, RUS-AUDIT item 2 standard-drink table. - Paused / held-for-review questionnaires get their own screen. - Today: intake and diary tasks, review notice, therapy-day card on days 1/7/14. - Drug card /meds/:ref from data/meds/meds_reference.json (draft built from the Minzdrav guidelines: depression 2024, PTSD 2023) — expected effect, course, side effects, red flags; no doses shown. "Report a side effect" always available (med:side_effects:<ref>). - API: /instruments/catalog, /meds/reference; today gains questionnaire state, reference id, indication and therapy day; demo persona seeds the dashboard dose history. - INTAKE_DEMO=1 (demo clock only) opens the questionnaires on synthetic data without touching the clinical release gate in config/intake_runtime.yaml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { api } from "../api/client";
|
||||
import type { Catalog, MedsReference } from "../api/types";
|
||||
|
||||
/*
|
||||
* Static reference data from the server (questionnaire catalog, drug reference): fetched once per app run and
|
||||
* shared by every screen. A failed fetch is retried on the next mount; screens work without it, only less rich.
|
||||
*/
|
||||
|
||||
function cached<T>(load: () => Promise<T>) {
|
||||
let value: T | null = null;
|
||||
let inflight: Promise<T> | null = null;
|
||||
const get = () => {
|
||||
inflight ??= load().then(
|
||||
(v) => (value = v),
|
||||
(e) => {
|
||||
inflight = null;
|
||||
throw e;
|
||||
},
|
||||
);
|
||||
return inflight;
|
||||
};
|
||||
return function useCached(): T | null {
|
||||
const [v, setV] = useState<T | null>(value);
|
||||
useEffect(() => {
|
||||
if (value) return;
|
||||
let alive = true;
|
||||
get()
|
||||
.then((x) => alive && setV(x))
|
||||
.catch(() => undefined);
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, []);
|
||||
return v;
|
||||
};
|
||||
}
|
||||
|
||||
export const useCatalog = cached<Catalog>(api.catalog);
|
||||
export const useMedsReference = cached<MedsReference>(api.medsReference);
|
||||
Reference in New Issue
Block a user