fix(encounters): give the visit form's link pickers their own query keys

The visit form's lab and episode pickers fetched with their own page
sizes under the same keys as the Labs list and the illness pages, which
fetch with others. Whichever read landed first served the other: the
picker could see 50 episodes instead of 100, or the Labs list a 200-row
page as the whole list. The picker reads now have keys of their own,
under the lab and illness roots so writes still evict them.
This commit is contained in:
Marc-André Bombeck committed 2026-09-24 12:17:56 +02:00
1 parent aeb8930ce1
commit a2282a498c
4 files changed
+53 -9

No files matched your search

@@ -87,14 +87,7 @@ export function EncounterLinkPickers({
});
const labs = useQuery({
queryKey: queryKeys.labResultsList({
analyte: undefined,
panel: undefined,
from: undefined,
to: undefined,
page: 0,
sortDir: "desc",
}),
queryKey: queryKeys.labResultsPicker(PICKER_FETCH_LIMIT),
enabled: labsOn,
queryFn: () =>
apiGet<LabListPage>(
@@ -103,7 +96,7 @@ export function EncounterLinkPickers({
});
const episodes = useQuery({
queryKey: queryKeys.illnessEpisodes(true),
queryKey: queryKeys.illnessEpisodesPicker(EPISODE_FETCH_LIMIT),
enabled: illnessOn,
queryFn: () =>
apiGet<IllnessEpisodeDTO[]>(
@@ -0,0 +1,41 @@
/**
* One key, one fetch. The visit form's link pickers read labs and illness
* episodes with their own page size (200 results, 100 episodes), the Labs
* list and the illness hook with theirs (500, the route's default 50). Under
* a shared key whichever read landed first served the other, so the picker
* could offer 50 episodes or the Labs list could render a 200-row page as
* the whole list. The picker reads carry their own keys, still under the
* domain roots so a lab or episode write evicts them.
*/
import { describe, expect, it } from "vitest";
import { queryKeys } from "@/lib/query-keys";
const LIST_PARAMS = {
analyte: undefined,
panel: undefined,
from: undefined,
to: undefined,
page: 0,
sortDir: "desc",
} as const;
describe("the link pickers' reads have keys of their own", () => {
it("labs: differs from the Labs list and sits under the lab root", () => {
const key = queryKeys.labResultsPicker(200);
expect(key).not.toEqual(queryKeys.labResultsList(LIST_PARAMS));
expect(key.slice(0, 1)).toEqual(queryKeys.labResults());
});
it("episodes: differs from the illness list and sits under the illness root", () => {
const key = queryKeys.illnessEpisodesPicker(100);
expect(key).not.toEqual(queryKeys.illnessEpisodes(true));
expect(key.slice(0, 1)).toEqual(queryKeys.illness());
});
it("a different page size is a different key", () => {
expect(queryKeys.labResultsPicker(200)).not.toEqual(
queryKeys.labResultsPicker(500),
);
});
});
+4
View File
@@ -15,6 +15,10 @@ export const illnessKeys = {
illness: () => ["illness"] as const,
illnessEpisodes: (includeResolved: boolean) =>
["illness", "episodes", includeResolved] as const,
// The visit form's episode picker, with its own page size (the illness
// pages read the route's default); a shared key would serve one to the other.
illnessEpisodesPicker: (limit: number) =>
["illness", "episodes-picker", limit] as const,
illnessEpisode: (id: string) => ["illness", "episode", id] as const,
illnessDayLog: (episodeId: string, date: string) =>
["illness", "day-log", episodeId, date] as const,
+6
View File
@@ -29,6 +29,12 @@ export const labKeys = {
params.sortDir,
] as const,
// The visit form's lab picker: newest results, its own page size. Its own
// key because the Labs list reads a different page size, and a shared key
// would serve one read's page to the other.
labResultsPicker: (limit: number) =>
["lab-results", "picker", limit] as const,
// v1.25 — paginated (offset) reading feed for the biomarker detail page.
// Distinct from `labResultsList` (single-page key) so the infinite-query
// accumulation never collides with a single-page read. Shares the