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
34 changes: 20 additions & 14 deletions src/components/therapy-compass/screens/search-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
} from "@/components/clinical-dashboard/result-filter-control";
import { pageContainer } from "@/components/ui-primitives";
import { therapyScreenHref } from "@/lib/therapy-compass-navigation";
import { isAdministratorUser } from "@/lib/authorization";
import { useAuthIfAvailable } from "@/lib/example-data/store";

import { useTcBindings } from "../bindings";
import { matchesAvailability, matchesTopics } from "../data/select";
Expand All @@ -34,6 +36,7 @@ const MAX_CARDS = 24;

export function SearchScreen() {
const b = useTcBindings();
const isAdministrator = isAdministratorUser(useAuthIfAvailable()?.session?.user);
const q = b.search.query;
// Nothing typed is browsing, not a search: show the list A to Z with no
// "Best match" or "Why matched", so it never reads as the app having picked
Expand Down Expand Up @@ -300,20 +303,23 @@ export function SearchScreen() {
) : null}

{/* The sign-off queue left the main tabs (it is editorial work, not a
clinical destination). This quiet link keeps it one tap away. */}
<p className="m-0 pt-2">
<Link
href={b.workspaceHref(therapyScreenHref("review"))}
data-testid="therapy-review-queue-link"
className="inline-flex min-h-tap items-center gap-2 rounded-lg px-1 text-sm-minus font-semibold text-[color:var(--text-muted)] hover:text-[color:var(--text)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]"
>
<ClipboardCheck aria-hidden="true" className="size-icon-md shrink-0" />
Review queue
{b.loading || b.error ? null : (
<span className="nums text-[color:var(--text-muted)]">· {b.reviewCount} to review</span>
)}
</Link>
</p>
clinical destination). This quiet link keeps it one tap away for a site
administrator, the only reader who can sign off (owner decision, 13 Oct 2026). */}
{isAdministrator ? (
<p className="m-0 pt-2">
<Link
href={b.workspaceHref(therapyScreenHref("review"))}
data-testid="therapy-review-queue-link"
className="inline-flex min-h-tap items-center gap-2 rounded-lg px-1 text-sm-minus font-semibold text-[color:var(--text-muted)] hover:text-[color:var(--text)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus)]"
>
<ClipboardCheck aria-hidden="true" className="size-icon-md shrink-0" />
Review queue
{b.loading || b.error ? null : (
<span className="nums text-[color:var(--text-muted)]">· {b.reviewCount} to review</span>
)}
</Link>
</p>
) : null}
</section>
);
}
7 changes: 4 additions & 3 deletions src/lib/mode-secondary-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ export const modeSecondaryNavigationRegistry = {
{ id: "recommend", label: "Recommend", href: "/therapy-compass/recommend" },
{ id: "compare", label: "Compare", href: "/therapy-compass/compare" },
{ id: "pathways", label: "Pathways", href: "/therapy-compass/pathways" },
// The qualified-clinician sign-off queue. It becomes `audience: "administrators"` once the owner's
// account carries the site administrator role; until then hiding it would hide it from the owner too.
// The qualified-clinician sign-off queue, listed for site administrators only (owner decision,
// 13 Oct 2026, once the owner's account carried the role). The route still opens for anyone and
// the server still refuses a sign-off from anyone else.
// `group: "more"` keeps it registered (the route, the pill name, `activeId`) but off the main
// tabs, which list only ungrouped entries (owner decision, October 2026). The Therapy search
// page links to it, so it stays one tap away.
{ id: "review", label: "Review", href: "/therapy-compass/review", group: "more" },
{ id: "review", label: "Review", href: "/therapy-compass/review", group: "more", audience: "administrators" },
],
// Two genuinely distinct surfaces: `/factsheets/search` (query + filters +
// result rows) and `/factsheets/topics` (category browse). Search leads, the
Expand Down
8 changes: 8 additions & 0 deletions tests/mode-secondary-navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,14 @@ describe("mode secondary navigation registry", () => {
}
});

it("lists Therapy's sign-off queue for site administrators only", () => {
const entries = modeSecondaryNavigationEntries("therapy-compass");
const ids = (isAdministrator: boolean) =>
visibleModeSecondaryNavigationEntries(entries, { isEditor: true, isAdministrator }).map((entry) => entry.id);
expect(ids(false)).not.toContain("review");
expect(ids(true)).toContain("review");
});

it("names the right On Call page in the pill, including the two editors and the picker", () => {
const cases: Record<string, string | null> = {
"/on-call": "now",
Expand Down
16 changes: 15 additions & 1 deletion tests/therapy-compact-row.dom.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ function therapy(overrides: Partial<Therapy> = {}): Therapy {
}

const bindingsState = vi.hoisted(() => ({ results: [] as Therapy[] }));
const authState = vi.hoisted(() => ({ siteRole: undefined as string | undefined }));

vi.mock("@/lib/example-data/store", () => ({
useAuthIfAvailable: () => ({ session: { user: { app_metadata: { site_role: authState.siteRole } } } }),
}));

vi.mock("@/components/therapy-compass/bindings", () => ({
useTcBindings: () => ({
Expand Down Expand Up @@ -118,8 +123,9 @@ describe("Therapy compact rows", () => {
}
});

it("keeps the Review queue one tap away now that it has left the main tabs", () => {
it("keeps the Review queue one tap away for a site administrator", () => {
bindingsState.results = [therapy()];
authState.siteRole = "administrator";
render(<SearchScreen />);

const link = screen.getByTestId("therapy-review-queue-link");
Expand All @@ -128,6 +134,14 @@ describe("Therapy compact rows", () => {
expect(link).toHaveTextContent("12 to review");
});

it("leaves the Review queue link out for anyone who is not a site administrator", () => {
bindingsState.results = [therapy()];
authState.siteRole = undefined;
render(<SearchScreen />);

expect(screen.queryByTestId("therapy-review-queue-link")).toBeNull();
});

it("still shows what the row used for Best used for and Best fit, word for word, in the record", () => {
const record = therapy();
render(<TherapyRecordSections therapy={record} />);
Expand Down
Loading