diff --git a/src/components/clinical-dashboard/document-results.tsx b/src/components/clinical-dashboard/document-results.tsx index 4c31829567..1b44455d3e 100644 --- a/src/components/clinical-dashboard/document-results.tsx +++ b/src/components/clinical-dashboard/document-results.tsx @@ -1,18 +1,110 @@ "use client"; import Link from "next/link"; -import { BookOpen } from "lucide-react"; +import { BookOpen, FileImage, Filter, ListChecks } from "lucide-react"; import { DocumentOrganizationBadges, documentDisplayTitle } from "@/components/DocumentOrganizationBadges"; import { DocumentTagCloud } from "@/components/DocumentTagCloud"; import { SafeBoldText } from "@/components/SafeBoldText"; import { UtilityDrawer } from "@/components/clinical-dashboard/dashboard-shell"; +import { DocumentBadge, DocumentFileTile, documentFileKind } from "@/components/clinical-dashboard/document-ui"; import { cn, floatingControl, sourceCard, textMuted } from "@/components/ui-primitives"; import { type SmartDocumentTag } from "@/lib/document-tags"; import type { RelatedDocument } from "@/lib/types"; export { StagedAnswerResultSurface } from "@/components/clinical-dashboard/answer-result-surface"; +// Compact page label so the metadata pill stays a single glanceable token on +// phones: "p.12" for one page, "p.12 +2" when several pages matched. +function relatedPageLabel(pages: number[]) { + const valid = pages.filter((page) => Number.isFinite(page)); + if (valid.length === 0) return "Page n/a"; + if (valid.length === 1) return `p.${valid[0]}`; + return `p.${valid[0]} +${valid.length - 1}`; +} + +function relatedDocumentHref(document: RelatedDocument) { + const params = new URLSearchParams(); + params.set("page", String(document.best_pages[0] ?? 1)); + const chunkId = document.best_chunk_ids[0]; + if (chunkId) params.set("chunk", chunkId); + return `/documents/${document.document_id}?${params.toString()}`; +} + +function RelatedDocumentCard({ + document, + onScopeDocument, + onTagSearch, +}: { + document: RelatedDocument; + onScopeDocument: (documentId: string) => void; + onTagSearch: (tag: SmartDocumentTag) => void; +}) { + const title = documentDisplayTitle(document); + const imageCount = document.image_count ?? 0; + const tableCount = document.table_count ?? 0; + const metaPill = "min-h-6 rounded-md px-2"; + // Site and document-type are already surfaced by the governance badges above, + // so drop them from the tag cloud to avoid showing the same chip twice. + const tagCloudLabels = document.labels.filter( + (label) => label.label_type !== "site" && label.label_type !== "document_type", + ); + + return ( +
+
+ +
+

+ {document.match_reason} +

+ + {title} + +
+ +
+ +
+ + {relatedPageLabel(document.best_pages)} + + {imageCount > 0 ? ( + + {imageCount} image{imageCount === 1 ? "" : "s"} + + ) : null} + {tableCount > 0 ? ( + + {tableCount} table{tableCount === 1 ? "" : "s"} + + ) : null} +
+ + + + {document.summary ? ( +

+ +

+ ) : null} + + +
+ ); +} + export function RelatedDocumentsPanel({ documents, onScopeDocument, @@ -31,38 +123,14 @@ export function RelatedDocumentsPanel({ summary={`${documents.length} broader document match${documents.length === 1 ? "" : "es"}`} mobileSummary={`${documents.length} related`} > -
+
{documents.map((document) => ( -
-
-
- - {documentDisplayTitle(document)} - - -

- {document.match_reason} · pages {document.best_pages.join(", ") || "n/a"} · {document.image_count}{" "} - images{document.table_count ? ` · ${document.table_count} tables` : ""} -

-
- -
- {document.summary && ( -

- -

- )} - -
+ ))}