mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(documents): vault list contract on the client
URL-backed facets (q / kind / episode / year) parse and serialise through one pure helper pair so deep links round-trip byte-stable; the API search builder pins the timeline sort. Month bucketing + row chunking feed the virtualized grid as a flat item list. The upload-response parser owns the duplicate contract: HTTP 200 with envelope-level meta.duplicate returns the existing row, every 413/415 reason maps to a translated-copy class, and proxy-stripped bodies fall back to the HTTP status. Query keys move to the vault filter shape and gain the usage read. Plan-Task: W2-T1 (URL state), W2-T5 (keys)
This commit is contained in:
1 parent
b1004958c3
commit
37e9d933e2
4 files changed
+636
-24
No files matched your search
@@ -1,42 +1,47 @@
|
||||
/**
|
||||
* Query keys — clinical documents library (v1.25, W-DOCS-IN): the browsable
|
||||
* document list (search / category filter / sort, keyset-paginated) and a
|
||||
* single document's detail (document + staged facts). Part of the centralized
|
||||
* factory; aggregated in `./index.ts`. Any document write (upload / edit /
|
||||
* extract / confirm / discard) invalidates the `["documents"]` prefix so the
|
||||
* list and the open detail repaint in lockstep.
|
||||
* Query keys — the Dokumente vault: the filtered timeline list (keyset-
|
||||
* paginated), a single document's detail, and the usage/limits read the
|
||||
* upload path pre-flights against. Part of the centralized factory;
|
||||
* aggregated in `./index.ts`. Any document write (upload / edit / link /
|
||||
* delete / restore / bulk) invalidates the `["documents"]` prefix so the
|
||||
* timeline, an open detail sheet, and the quota bar repaint in lockstep.
|
||||
*/
|
||||
import type {
|
||||
DocumentListSort,
|
||||
InboundDocumentKindValue,
|
||||
} from "@/lib/validations/inbound-documents";
|
||||
import type { InboundDocumentKindValue } from "@/lib/validations/inbound-documents";
|
||||
|
||||
/**
|
||||
* The parameter set that distinguishes one library list view from another.
|
||||
* Lives in the key so two different filter/sort combinations never share a
|
||||
* cache bucket. `undefined` fields are dropped by TanStack's stable hash, so a
|
||||
* bare `{ sort, order }` and `{ q: undefined, kind: undefined, sort, order }`
|
||||
* resolve to the same key.
|
||||
* The parameter set that distinguishes one vault timeline view from another —
|
||||
* mirrors the URL facets (`?q&kind&episode&year`) one-to-one so a deep link
|
||||
* and an in-page filter change resolve to the same cache bucket. `undefined`
|
||||
* fields are dropped by TanStack's stable hash, so an all-defaults view and
|
||||
* an explicit `{ q: undefined, … }` share a key. Sort is pinned server-side
|
||||
* (filing date, newest first) and is deliberately NOT part of the key.
|
||||
*/
|
||||
export interface DocumentListParams {
|
||||
export interface DocumentVaultFilters {
|
||||
q?: string;
|
||||
kind?: InboundDocumentKindValue;
|
||||
from?: string;
|
||||
to?: string;
|
||||
sort: DocumentListSort;
|
||||
order: "asc" | "desc";
|
||||
/** Type facet — OR inside the facet, sorted before keying by the caller. */
|
||||
kinds?: InboundDocumentKindValue[];
|
||||
/** Only documents linked to this illness/condition episode. */
|
||||
episodeId?: string;
|
||||
/** Only documents whose filing date falls in this calendar year. */
|
||||
year?: number;
|
||||
}
|
||||
|
||||
export const documentKeys = {
|
||||
documents: () => ["documents"] as const,
|
||||
inboundDocuments: () => ["documents", "inbound"] as const,
|
||||
/**
|
||||
* The parameterised library list (keyset-paginated via `useInfiniteQuery`).
|
||||
* The parameterised vault list (keyset-paginated via `useInfiniteQuery`).
|
||||
* The literal `"list"` segment keeps it distinct from a single-document key
|
||||
* (`inboundDocument(id)`); cuid ids never collide with it. Stays under the
|
||||
* `["documents", "inbound"]` prefix so prefix invalidation still reaches it.
|
||||
*/
|
||||
inboundDocumentList: (params: DocumentListParams) =>
|
||||
["documents", "inbound", "list", params] as const,
|
||||
inboundDocumentList: (filters: DocumentVaultFilters) =>
|
||||
["documents", "inbound", "list", filters] as const,
|
||||
inboundDocument: (id: string) => ["documents", "inbound", id] as const,
|
||||
/**
|
||||
* Storage usage + effective limits (`GET /api/documents/inbound/usage`).
|
||||
* Invalidated through the `["documents"]` prefix after every upload /
|
||||
* delete so the quota bar tracks reality.
|
||||
*/
|
||||
inboundDocumentUsage: () => ["documents", "inbound", "usage"] as const,
|
||||
};
|
||||
Reference in new issue
Block a user