Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/codebase-index.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,7 +45,7 @@ Structured map for AI agents and onboarding. For live routes, see `docs/site-map
- **PWA:** `docs/pwa.md` — install assets, privacy-first service worker/offline shell, lifecycle, security, and verification
- **Home:** `src/app/page.tsx` — dashboard rendered by shell
- **Dashboard:** `src/components/ClinicalDashboard.tsx` + `src/components/clinical-dashboard/`
- **Modes (12):** `src/lib/app-modes.ts` — answer, documents, services, forms, favourites, differentials, DSM-5 diagnosis, specifiers, formulation, prescribing, tools, Therapy Compass
- **Modes (13):** `src/lib/app-modes.ts` — answer, documents, services, forms, favourites, differentials, DSM-5 diagnosis, specifiers, formulation, prescribing, tools, Therapy mode, Factsheets

### Product pages (`src/app/`)

Expand Down
2 changes: 1 addition & 1 deletion docs/site-map.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,7 +31,7 @@ This file is generated by `npm run sitemap:update`. Run `npm run sitemap:check`
- `/specifiers/builder` - Structured diagnostic wording builder. Source: `src/app/specifiers/builder/page.tsx`.
- `/specifiers/compare` - Side-by-side psychiatric specifier comparison. Source: `src/app/specifiers/compare/page.tsx`.
- `/specifiers/map` - Psychiatric specifier family map. Source: `src/app/specifiers/map/page.tsx`.
- `/therapy-compass` - Therapy Compass home (source-grounded therapy decision support). Source: `src/app/therapy-compass/page.tsx`.
- `/therapy-compass` - Therapy mode home (source-grounded therapy decision support). Source: `src/app/therapy-compass/page.tsx`.
- `/therapy-compass/[slug]/brief` - Therapy brief-intervention view. Source: `src/app/therapy-compass/[slug]/brief/page.tsx`.
- `/therapy-compass/[slug]/sheet` - Therapy patient-sheet builder. Source: `src/app/therapy-compass/[slug]/sheet/page.tsx`.
- `/therapy-compass/compare` - Side-by-side therapy comparison. Source: `src/app/therapy-compass/compare/page.tsx`.
Expand Down
14 changes: 8 additions & 6 deletions scripts/generate-site-map.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ const routeDescriptions: Record<string, string> = {
"/specifiers/builder": "Structured diagnostic wording builder.",
"/specifiers/compare": "Side-by-side psychiatric specifier comparison.",
"/specifiers/map": "Psychiatric specifier family map.",
"/therapy-compass": "Therapy Compass home (source-grounded therapy decision support).",
"/therapy-compass": "Therapy mode home (source-grounded therapy decision support).",
"/therapy-compass/search": "Therapy library search surface.",
"/therapy-compass/recommend": "Recommend a therapy from a clinical question and constraints.",
"/therapy-compass/compare": "Side-by-side therapy comparison.",
Expand DownExpand Up@@ -274,12 +274,14 @@ function renderModeRoutes() {
factsheets: appModeHomeHref("factsheets", { query: "sertraline", focus: true, run: true }),
};

return appModeDefinitions.map((mode) =>
bullet(
return appModeDefinitions.map((mode) => {
const modeName = mode.label.toLowerCase().endsWith(" mode") ? mode.label : `${mode.label} mode`;

return bullet(
("href" in mode ? mode.href : undefined) ?? appModeHomeHref(mode.id),
`${mode.label} mode. Search kind: \`${mode.search.kind}\`. Query example: \`${examples[mode.id]}\`.`,
),
);
`${modeName}. Search kind: \`${mode.search.kind}\`. Query example: \`${examples[mode.id]}\`.`,
);
});
}

type ModePageIndexRow = {
Expand Down
4 changes: 2 additions & 2 deletions src/app/therapy-compass/[slug]/brief/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,8 +15,8 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
return {
title:
record && record.briefInterventionAvailable
? `${record.name} · Brief intervention - Therapy Compass`
: "Therapy not found - Therapy Compass",
? `${record.name} · Brief intervention - Therapy mode`
: "Therapy not found - Therapy mode",
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/therapy-compass/[slug]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,10 +11,10 @@ export function generateStaticParams() {
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
const { slug } = await params;
const record = findTherapyRecord(slug);
if (!record) return { title: "Therapy not found - Therapy Compass" };
if (!record) return { title: "Therapy not found - Therapy mode" };
const summary = record.clinicalSummary ?? record.bestUsedFor ?? "Source-grounded therapy record.";
return {
title: `${record.name} - Therapy Compass`,
title: `${record.name} - Therapy mode`,
description: therapyNeedsReview(record) ? `${summary} (Awaiting source review.)` : summary,
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/therapy-compass/[slug]/sheet/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,8 +15,8 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
return {
title:
record && record.patientSheetAvailable
? `${record.name} · Patient sheet - Therapy Compass`
: "Therapy not found - Therapy Compass",
? `${record.name} · Patient sheet - Therapy mode`
: "Therapy not found - Therapy mode",
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/compare/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { CompareScreen } from "@/components/therapy-compass/screens/compare-screen";

export const metadata: Metadata = {
title: "Compare therapies - Therapy Compass",
title: "Compare therapies - Therapy mode",
description: "Compare therapies side by side on indications, delivery, evidence, and review status.",
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import { redirect } from "next/navigation";
import { HomeScreen } from "@/components/therapy-compass/screens/home-screen";

export const metadata: Metadata = {
title: "Therapy - Clinical KB",
title: "Therapy mode - Clinical KB",
description:
"Source-grounded therapy decision support: search, compare, recommend, pathways, brief interventions and patient sheets.",
};
Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/pathways/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { PathwaysScreen } from "@/components/therapy-compass/screens/pathways-screen";

export const metadata: Metadata = {
title: "Clinical pathways - Therapy Compass",
title: "Clinical pathways - Therapy mode",
description: "Problem-based, step-by-step therapy pathways linking source-grounded therapy records.",
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/recommend/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { RecommendScreen } from "@/components/therapy-compass/screens/recommend-screen";

export const metadata: Metadata = {
title: "Recommend a therapy - Therapy Compass",
title: "Recommend a therapy - Therapy mode",
description: "Match a clinical question and constraints to ranked, source-grounded therapy options.",
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/review/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { OtherScreen } from "@/components/therapy-compass/screens/other-screen";

export const metadata: Metadata = {
title: "Review queue - Therapy Compass",
title: "Review queue - Therapy mode",
description: "Therapy records still awaiting qualified-clinician source review.",
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/therapy-compass/search/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { Metadata } from "next";
import { SearchScreen } from "@/components/therapy-compass/screens/search-screen";

export const metadata: Metadata = {
title: "Search therapies - Therapy Compass",
title: "Search therapies - Therapy mode",
description: "Search the source-grounded therapy library by problem, symptom, skill, or population.",
};

Expand Down
9 changes: 7 additions & 2 deletions src/components/clinical-dashboard/ClinicalSidebar.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,7 +41,7 @@ function useClientMounted() {
);
}
import { Sheet } from "@/components/ui/sheet";
import { type AppModeId, isAppModeId, isAppModeVisible } from "@/lib/app-modes";
import { appModeDefinition, type AppModeId, isAppModeId, isAppModeVisible } from "@/lib/app-modes";
import { type ResolvedTheme } from "@/lib/theme";

export type SidebarIdentity = {
Expand DownExpand Up@@ -81,7 +81,12 @@ const sidebarToolItems = [
{ id: "formulation", label: "Formulation", icon: Network, href: "/formulation" },
{ id: "prescribing", label: "Medication", icon: Pill, href: "/?mode=prescribing" },
{ id: "tools", label: "Tools", icon: Wrench, href: "/?mode=tools" },
{ id: "therapy-compass", label: "Therapy", icon: appModeIcons["therapy-compass"], href: "/therapy-compass" },
{
id: "therapy-compass",
label: appModeDefinition("therapy-compass").label,
icon: appModeIcons["therapy-compass"],
href: "/therapy-compass",
},
{ id: "factsheets", label: "Factsheets", icon: appModeIcons.factsheets, href: "/factsheets" },
] as const;

Expand Down
2 changes: 1 addition & 1 deletion src/components/therapy-compass/screens/home-screen.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,7 +33,7 @@ export function HomeScreen() {
<ModeHomeMain testId="therapy-compass-home" contentAlign="startOnPhone">
<ModeHomeTemplate
testId="therapy-compass"
title="Therapy"
title="Therapy mode"
subtitle={therapyCountCopy}
icon={Search}
actionsLabel="Therapy workflows"
Expand Down
2 changes: 1 addition & 1 deletion src/components/therapy-compass/workspace.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,7 +26,7 @@ function TherapyCompassDataError() {
const b = useTcBindings();
return (
<section role="alert" aria-live="assertive" aria-busy={b.loading} className="tc-workspace-002">
<h1 className="tc-workspace-003">Therapy Compass could not load</h1>
<h1 className="tc-workspace-003">Therapy mode could not load</h1>
<p className="tc-workspace-004">
The therapy catalogue is unavailable. No results are being shown as a substitute.
</p>
Expand Down
10 changes: 5 additions & 5 deletions src/lib/app-modes.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -311,7 +311,7 @@ export const appModeDefinitions = [
},
{
id: "therapy-compass",
label: "Therapy",
label: "Therapy mode",
Comment thread
BigSimmo marked this conversation as resolved.
Comment thread
BigSimmo marked this conversation as resolved.
description: "Source-grounded therapy decision support",
href: "/therapy-compass",
// Cleared for production discovery: the re-curated therapy pathways have
Expand All@@ -324,15 +324,15 @@ export const appModeDefinitions = [
kind: "tools",
placeholder: "Search therapies, symptoms, or skills...",
inputAriaLabel: "Search therapies by problem, symptom, skill, or population",
submitIdleLabel: "Therapy",
submitBusyLabel: "Therapy",
submitAriaLabel: "Open Therapy",
submitIdleLabel: "Therapy mode",
submitBusyLabel: "Therapy mode",
submitAriaLabel: "Open Therapy mode",
emptyTitle: "Browse the therapy library",
readyTitle: "Search source-grounded therapies",
progressLabel: "Loading the therapy library.",
resultKind: "tools",
resultHeading: "Therapies",
statusLabel: "Therapy",
statusLabel: "Therapy mode",
nextStep: "Open a therapy record",
badgeLabel: null,
},
Expand Down
10 changes: 5 additions & 5 deletions tests/therapy-compass-data-recovery.dom.test.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,12 +61,12 @@ describe("Therapy Compass required data recovery", () => {
expect(await screen.findByRole("status")).toHaveTextContent("Loading therapy library…");
expect(screen.getAllByRole("main")).toHaveLength(1);
expect(screen.queryByText(/Source-grounded therapy records\./)).not.toBeInTheDocument();
expect(screen.queryByRole("heading", { name: "Therapy" })).not.toBeInTheDocument();
expect(screen.queryByRole("heading", { name: "Therapy mode" })).not.toBeInTheDocument();

release(undefined);

await waitFor(() => expect(screen.getByText(/1 source-grounded therapy record\./)).toBeInTheDocument());
expect(screen.getByRole("heading", { name: "Therapy" })).toBeInTheDocument();
expect(screen.getByRole("heading", { name: "Therapy mode" })).toBeInTheDocument();
expect(screen.getAllByRole("main")).toHaveLength(1);
expect(screen.queryByText(/Source-grounded therapy records\./)).not.toBeInTheDocument();
});
Expand All@@ -92,13 +92,13 @@ describe("Therapy Compass required data recovery", () => {
expect(screen.queryByText(/Source-grounded therapy records\./)).not.toBeInTheDocument();
expect(screen.queryByRole("heading", { name: "Frequently used therapies" })).not.toBeInTheDocument();

expect(await screen.findByRole("alert")).toHaveTextContent("Therapy Compass could not load");
expect(screen.queryByRole("heading", { name: "Therapy" })).not.toBeInTheDocument();
expect(await screen.findByRole("alert")).toHaveTextContent("Therapy mode could not load");
expect(screen.queryByRole("heading", { name: "Therapy mode" })).not.toBeInTheDocument();

failTherapies = false;
fireEvent.click(screen.getByRole("button", { name: "Retry" }));

expect(await screen.findByRole("heading", { name: "Therapy" })).toBeInTheDocument();
expect(await screen.findByRole("heading", { name: "Therapy mode" })).toBeInTheDocument();
expect(screen.getByText(/1 source-grounded therapy record\./)).toBeInTheDocument();
expect(screen.queryByRole("alert")).not.toBeInTheDocument();
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(2));
Expand Down
39 changes: 39 additions & 0 deletions tests/therapy-compass-mode-wiring.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,8 +12,47 @@ const loaderSrc = readFileSync(
"utf8",
);
const dataDir = new URL("../public/therapy-compass-data/", import.meta.url);
const therapyMetadataFiles = [
"../src/app/therapy-compass/page.tsx",
"../src/app/therapy-compass/search/page.tsx",
"../src/app/therapy-compass/recommend/page.tsx",
"../src/app/therapy-compass/compare/page.tsx",
"../src/app/therapy-compass/pathways/page.tsx",
"../src/app/therapy-compass/review/page.tsx",
"../src/app/therapy-compass/[slug]/page.tsx",
"../src/app/therapy-compass/[slug]/brief/page.tsx",
"../src/app/therapy-compass/[slug]/sheet/page.tsx",
];

describe("Therapy Compass production-mode wiring", () => {
it("uses Therapy mode for user-facing mode copy and page metadata", () => {
const appModesSrc = readFileSync(new URL("../src/lib/app-modes.ts", import.meta.url), "utf8");
const homeSrc = readFileSync(
new URL("../src/components/therapy-compass/screens/home-screen.tsx", import.meta.url),
"utf8",
);
const workspaceSrc = readFileSync(
new URL("../src/components/therapy-compass/workspace.tsx", import.meta.url),
"utf8",
);
const sidebarSrc = readFileSync(
new URL("../src/components/clinical-dashboard/ClinicalSidebar.tsx", import.meta.url),
"utf8",
);

expect(appModesSrc).toContain('label: "Therapy mode"');
expect(appModesSrc).toContain('submitAriaLabel: "Open Therapy mode"');
expect(homeSrc).toContain('title="Therapy mode"');
expect(workspaceSrc).toContain("Therapy mode could not load");
expect(sidebarSrc).toContain('label: appModeDefinition("therapy-compass").label');

for (const filename of therapyMetadataFiles) {
const source = readFileSync(new URL(filename, import.meta.url), "utf8");
expect(source, filename).toContain("Therapy mode");
expect(source, filename).not.toContain("Therapy Compass");
}
});

it("loads its dataset from a non-/mockups path (proxy.ts 404s every /mockups path in production)", () => {
const base = loaderSrc.match(/const BASE = "([^"]+)"/)?.[1];
expect(base).toBeTruthy();
Expand Down
2 changes: 1 addition & 1 deletion tests/ui-accessibility.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -445,7 +445,7 @@ test.describe("Clinical KB accessibility coverage", () => {
await page.setViewportSize({ width: 390, height: 844 });
await page.goto("/therapy-compass", { waitUntil: "domcontentloaded" });

await expect(page.getByRole("heading", { name: "Therapy", exact: true })).toBeVisible({
await expect(page.getByRole("heading", { name: "Therapy mode", exact: true })).toBeVisible({
timeout: 60_000,
});

Expand Down
2 changes: 1 addition & 1 deletion tests/ui-route-coverage.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -218,7 +218,7 @@ test.describe("previously uncovered production routes", () => {
"/therapy-compass",
async (currentPage) => {
await expect(currentPage.getByRole("main")).toBeVisible();
await expect(currentPage.getByRole("heading", { name: "Therapy", level: 1, exact: true })).toBeVisible({
await expect(currentPage.getByRole("heading", { name: "Therapy mode", level: 1, exact: true })).toBeVisible({
timeout: 30_000,
});
},
Expand Down
Loading