diff --git a/docs/branch-review-records/92610868c245fa3f12c1f952f99050f4632920a5e95b42b678790e93fabb0050.record.md b/docs/branch-review-records/92610868c245fa3f12c1f952f99050f4632920a5e95b42b678790e93fabb0050.record.md new file mode 100644 index 0000000000..1e85e5679a --- /dev/null +++ b/docs/branch-review-records/92610868c245fa3f12c1f952f99050f4632920a5e95b42b678790e93fabb0050.record.md @@ -0,0 +1 @@ +| 2026-08-18 | claude/diagnostic-criteria-duplication-udg99e | 89d6320fcec94153af3f280683190f02d2e7f172 | dsm diagnosis page criteria duplication | fixed: replaced criteria-echo card row with a four-tile at-a-glance summary; criteria list, sidebar and nav anchors untouched | test:focused 38 passed; vitest dsm 13 passed; typecheck; lint; check:design-system-contract (legacy shadow aliases 89, unchanged); rendered proof on 4 records | diff --git a/src/components/dsm/dsm-diagnosis-page.tsx b/src/components/dsm/dsm-diagnosis-page.tsx index d2f7ef8e75..4020e23da4 100644 --- a/src/components/dsm/dsm-diagnosis-page.tsx +++ b/src/components/dsm/dsm-diagnosis-page.tsx @@ -1,10 +1,12 @@ import Link from "next/link"; +import type { ComponentType } from "react"; import { BookOpenCheck, ChevronRight, Search, ClipboardList, GitCompareArrows, + Gauge, ListChecks, MessageSquareText, ShieldCheck, @@ -19,6 +21,43 @@ import { inPageActionRowClass, inPageAnchor } from "@/components/in-page-nav/in- import { cn, codeText, metadataPill, pageContainer } from "@/components/ui-primitives"; import { dsmCriteria, resolveDsmDifferential, type DsmDiagnosis, type DsmLabeledText } from "@/lib/dsm"; +/** + * Explicit singular and plural rather than appending "s", because the one that + * matters here is irregular: "1 criterion" / "4 criteria". + * + * The zero branch is unreachable in the shipped catalogue — criteria, specifiers + * and differentials are each populated on all 146 records — but the JSON is a + * vendored upstream snapshot, so a re-export could introduce one and "0 criteria" + * would read as a rendering fault rather than as a fact about the record. + */ +function countLabel(count: number, singular: string, plural: string) { + if (count === 0) return "None in this record"; + return `${count} ${count === 1 ? singular : plural}`; +} + +/** One label/value pair in the at-a-glance row. Non-interactive by design. */ +function SummaryTile({ + icon: Icon, + label, + value, +}: { + icon: ComponentType<{ className?: string }>; + label: string; + value: string; +}) { + return ( +
+
+ + {label} +
+
+ {value} +
+
+ ); +} + function CriteriaRow({ criterion, index }: { criterion: DsmLabeledText; index: number }) { return (
  • @@ -39,6 +78,19 @@ export function DsmDiagnosisPage({ diagnosis }: { diagnosis: DsmDiagnosis }) { const criteria = dsmCriteria(diagnosis); const compareHref = `/dsm/compare?ids=${encodeURIComponent(diagnosis.slug)}`; + // "4 criteria, A-D" / "1 criterion, A". Twelve records carry a single criterion, + // so the range is appended only when there are at least two to span — otherwise + // it would read "A-A". Labels fall back to the ordinal the list rows already use. + const criteriaCountLabel = countLabel(criteria.length, "criterion", "criteria"); + const firstCriterionLabel = criteria[0]?.label || "1"; + const lastCriterionLabel = criteria.at(-1)?.label || String(criteria.length); + const criteriaSummary = + criteria.length > 1 + ? `${criteriaCountLabel}, ${firstCriterionLabel}\u2013${lastCriterionLabel}` + : criteria.length === 1 + ? `${criteriaCountLabel}, ${firstCriterionLabel}` + : criteriaCountLabel; + return ( <>
    -
    - {criteria.slice(0, 4).map((criterion, index) => ( -
    -

    - Criterion {criterion.label || index + 1} -

    -

    - {criterion.text} -

    -
    - ))} + {/* + The shape of the record, not its content. This row previously rendered + `criteria.slice(0, 4)` verbatim, which the `#criteria` panel below already + lists in full — so every diagnosis stated its criteria twice, the second + time truncated. It also rendered `min(criteria.length, 4)` cards, and only + 86 of 146 records carry four or more criteria, so the row was a ragged one + to four tiles rather than a stable strip. + + Every field read here is populated on all 146 records, so this is always + exactly four tiles. `icd_code` and the category are deliberately absent: + the page header already carries both as chips, and repeating them would be + the same defect in a new place. + */} +
    +
    + + + + +