mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
feat(encounters): the lab moment, the condition side, and closing a checkup
A lab panel files itself against the visit it came from, and never has to. The OCR review and the manual form both offer the suggestion through the one shared field, anchored on the draw date rather than on now, so backdating a reading moves the offer with it. The commit writes one link PER RESULT ROW, which is why the join is m:n: a marker re-run on a different day belongs to its own visit. Best-effort by design — the readings are the write that matters and must not be lost to a link that could not be made. The condition side gets a Visits about this card with an action that pre-links the episode. From the episode side only, and that is a decision: an episode spans weeks and a visit is a point, so matching the other way would be wrong often enough to teach a person to ignore every suggestion in the product. A due checkup gains a second action beside erledigt. Filing the visit as done satisfies the checkup through the same forward-only, idempotent primitive the checkbox uses, so doing both is one satisfaction and no error. The two actions answer different questions — one says it happened, the other says where. An appointment now appears where a person looks, and NEITHER surface relaxes the reminder-table exclusion that keeps it out of the preventive-care lists. Both read the visit table: a quiet line under the dashboard checkup block for anything inside two weeks, and one rail item for today or tomorrow. A diff in either that touches origin is the wrong fix. A visit write now also refreshes the reminder reads. Closing a checkup moves its next-due date on three surfaces that would otherwise keep showing it due until their own poll. OpenAPI regenerated in the same commit.
This commit is contained in:
1 parent
be9c79974f
commit
c47122ccfe
36 files changed
+924
-192
No files matched your search
@@ -15,6 +15,7 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiDelete, apiGet, apiPatch, apiPost } from "@/lib/api/api-fetch";
|
||||
import { invalidateReminderReads } from "@/hooks/use-measurement-reminders";
|
||||
import {
|
||||
encounterDependentKeys,
|
||||
invalidateKeys,
|
||||
@@ -44,17 +45,29 @@ const BASE = "/api/encounters";
|
||||
|
||||
export function useEncounters(
|
||||
enabled = true,
|
||||
window?: { from?: string; to?: string; status?: string },
|
||||
window?: {
|
||||
from?: string;
|
||||
to?: string;
|
||||
status?: string;
|
||||
/** Only visits filed against this condition episode. */
|
||||
episodeId?: string;
|
||||
},
|
||||
) {
|
||||
const from = window?.from ?? null;
|
||||
const to = window?.to ?? null;
|
||||
return useQuery({
|
||||
queryKey: queryKeys.encounterList(from, to, window?.status),
|
||||
queryKey: queryKeys.encounterList(
|
||||
from,
|
||||
to,
|
||||
window?.status,
|
||||
window?.episodeId,
|
||||
),
|
||||
queryFn: () => {
|
||||
const sp = new URLSearchParams();
|
||||
if (from) sp.set("from", from);
|
||||
if (to) sp.set("to", to);
|
||||
if (window?.status) sp.set("status", window.status);
|
||||
if (window?.episodeId) sp.set("episodeId", window.episodeId);
|
||||
const qs = sp.toString();
|
||||
return apiGet<EncounterList>(qs ? `${BASE}?${qs}` : BASE);
|
||||
},
|
||||
@@ -91,7 +104,24 @@ export function useEncounterSuggestion(anchor: string | null, enabled = true) {
|
||||
|
||||
export function useEncounterMutations() {
|
||||
const qc = useQueryClient();
|
||||
const invalidate = () => invalidateKeys(qc, encounterDependentKeys);
|
||||
/**
|
||||
* A visit write reaches further than the visit list.
|
||||
*
|
||||
* Filing one against a due checkup satisfies that reminder, which moves its
|
||||
* next-due date on the preventive-care list, on the dashboard card and on the
|
||||
* Today rail — three surfaces that read the reminder table and would
|
||||
* otherwise keep showing it due until their own poll. Booking one moves the
|
||||
* same reads the other way: a new appointment is a row the digest surfaces.
|
||||
*
|
||||
* So the fan-out is the visit roots PLUS the reminder reads, through the same
|
||||
* helper the Vorsorge surfaces use, rather than a second sweep that could
|
||||
* drift from it.
|
||||
*/
|
||||
const invalidate = () =>
|
||||
Promise.all([
|
||||
invalidateKeys(qc, encounterDependentKeys),
|
||||
invalidateReminderReads(qc),
|
||||
]);
|
||||
|
||||
const create = useMutation({
|
||||
mutationKey: queryKeys.encounterCreate(),
|
||||
|
||||
Reference in new issue
Block a user