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 src/app/services/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function ServicesIndexRoute({ searchParams }: { searchParam
readFirstSearchParam(resolvedSearchParams.query) ??
""
).trim();
const hasSubmittedSearch = resolvedSearchParams.run === "1" && query.length > 0;
const hasSubmittedSearch = readFirstSearchParam(resolvedSearchParams.run) === "1" && query.length > 0;

if (!hasSubmittedSearch) {
return <ServicesHomePage />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,10 @@ function isSourceBacked(item: FavouriteItem): boolean {
}

function toCommandItem(item: PrototypeFavouriteItem): FavouriteItem {
const type = typeByPrototypeType[item.type] ?? (item.primaryAction === "Run" ? "Saved search" : "Source");
const type =
item.type === "sources" && item.primaryAction === "Run"
? "Saved search"
: (typeByPrototypeType[item.type] ?? "Source");
return {
id: item.id,
title: item.title,
Expand Down Expand Up @@ -544,9 +547,11 @@ function FavouritesTable({
<label className="relative block min-w-[9.5rem]">
<span className="sr-only">Sort favourites</span>
<select
value={sortMode}
value={viewMode === "recent" ? "last-used" : sortMode}
disabled={viewMode === "recent"}
title={viewMode === "recent" ? "Recently used view is always sorted by last used" : undefined}
onChange={(event) => onSortModeChange(event.target.value as SortMode)}
className="h-9 w-full appearance-none rounded-lg border border-[color:var(--border)] bg-[color:var(--surface)] px-3 pr-9 text-xs font-bold text-[color:var(--text-muted)] outline-none hover:bg-[color:var(--surface-subtle)] focus:border-[color:var(--focus)] focus:ring-4 focus:ring-[color:var(--focus)]/20"
className="h-9 w-full appearance-none rounded-lg border border-[color:var(--border)] bg-[color:var(--surface)] px-3 pr-9 text-xs font-bold text-[color:var(--text-muted)] outline-none hover:bg-[color:var(--surface-subtle)] focus:border-[color:var(--focus)] focus:ring-4 focus:ring-[color:var(--focus)]/20 disabled:cursor-not-allowed disabled:opacity-60"
>
<option value="last-used">Sort: Last used</option>
<option value="title">Sort: Title</option>
Expand Down Expand Up @@ -897,7 +902,7 @@ export function FavouritesCommandLibraryPage({ query = "" }: { query?: string })

const continueItem = useMemo(() => getMostRecentlyUsedItem(items), [items]);
const showContinueStrip =
continueItem !== null && filteredItems.some((item) => item.id === continueItem.id) && filteredItems.length > 0;
continueItem !== null && scopedItems.some((item) => item.id === continueItem.id) && scopedItems.length > 0;

const selectedItem = selectedItemId ? (items.find((item) => item.id === selectedItemId) ?? null) : null;

Expand Down
15 changes: 12 additions & 3 deletions src/components/clinical-dashboard/favourites-library-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,32 @@ function buildSidebarSections({
label: "Source-backed",
count: sourceBackedCount,
active: viewMode === "source-backed",
onClick: () => onSelectViewMode(viewMode === "source-backed" ? "all" : "source-backed"),
onClick: () => {
onSelectSet(null);
onSelectViewMode(viewMode === "source-backed" ? "all" : "source-backed");
},
},
{
id: "pinned",
icon: Pin,
label: "Pinned",
count: pinnedCount,
active: viewMode === "pinned",
onClick: () => onSelectViewMode(viewMode === "pinned" ? "all" : "pinned"),
onClick: () => {
onSelectSet(null);
onSelectViewMode(viewMode === "pinned" ? "all" : "pinned");
},
},
{
id: "recent",
icon: Search,
label: "Recently used",
count: items.length,
active: viewMode === "recent",
onClick: () => onSelectViewMode(viewMode === "recent" ? "all" : "recent"),
onClick: () => {
onSelectSet(null);
onSelectViewMode(viewMode === "recent" ? "all" : "recent");
},
},
],
},
Expand Down
48 changes: 33 additions & 15 deletions src/components/forms/forms-search-results-page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import {
ChevronRight,
Clock3,
Expand All @@ -17,6 +18,7 @@ import {
} from "lucide-react";
import { useMemo } from "react";

import { appModeHomeHref } from "@/lib/app-modes";
import { rankFormRecords, type FormSearchMatch } from "@/lib/forms";
import { useRegistryRecords, type RegistryRequestStatus } from "@/lib/use-registry-records";
import {
Expand All @@ -38,13 +40,18 @@ type FormsSearchResultsPageProps = {
query: string;
};

const resultCodes = ["4A", "4B", "3A", "5", "2B", "1A"];
const formCodesBySlug: Record<string, string> = {
"transport-crisis-form": "4A",
"extension-transport-order": "4B",
"detention-examination-movement": "3A",
"transfer-order": "5",
};
const sourceSnippetCount = 278;
const taskCount = 8;
const pathwayCount = 12;

function resultCode(index: number) {
return resultCodes[index] ?? String(index + 1);
function resultCode(match: FormSearchMatch, index: number) {
return formCodesBySlug[match.service.slug] ?? String(index + 1);
}

function tagToneClass(label: string) {
Expand All @@ -61,10 +68,13 @@ function tagToneClass(label: string) {
return "bg-[color:var(--clinical-accent-soft)] text-[color:var(--clinical-accent)]";
}

function compactMatchReason(match: FormSearchMatch) {
if (match.reasons.includes("title")) return `Title or content match for "transport"`;
function compactMatchReason(match: FormSearchMatch, query: string) {
const trimmedQuery = query.trim();
if (match.reasons.includes("title")) {
return trimmedQuery ? `Title or content match for "${trimmedQuery}"` : "Title or content match";
}
if (match.reasons.includes("record fields")) return "Content match in related pathway";
return "Content match for transfer/transport";
return "Content match in the forms catalogue";
}

function ResultTabs({ formsCount }: { formsCount: number }) {
Expand Down Expand Up @@ -106,7 +116,7 @@ function ResultTabs({ formsCount }: { formsCount: number }) {
);
}

function ResultsTable({ matches }: { matches: FormSearchMatch[] }) {
function ResultsTable({ matches, query }: { matches: FormSearchMatch[]; query: string }) {
return (
<section
data-testid="form-search-results"
Expand All @@ -133,7 +143,7 @@ function ResultsTable({ matches }: { matches: FormSearchMatch[] }) {
className="grid gap-4 border-b border-[color:var(--border)] px-5 py-4 transition last:border-b-0 hover:bg-[color:var(--surface-subtle)]/55 md:grid-cols-[86px_minmax(180px,1fr)_170px_minmax(180px,1fr)_86px] md:items-center"
>
<div className="grid h-12 w-14 place-items-center rounded-lg border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] text-3xl font-extrabold text-[color:var(--clinical-accent)]">
{resultCode(index)}
{resultCode(match, index)}
</div>
<div>
<h3 className="max-w-[21rem] text-sm font-extrabold leading-snug text-[color:var(--text-heading)]">
Expand All @@ -157,7 +167,7 @@ function ResultsTable({ matches }: { matches: FormSearchMatch[] }) {
})}
</div>
<p className="text-sm font-medium leading-relaxed text-[color:var(--text-muted)]">
{compactMatchReason(match)}
{compactMatchReason(match, query)}
</p>
<Link
href={`/forms/${form.slug}`}
Expand Down Expand Up @@ -403,7 +413,7 @@ function VerifiedFooter() {
);
}

function MobileCards({ matches }: { matches: FormSearchMatch[] }) {
function MobileCards({ matches, query }: { matches: FormSearchMatch[]; query: string }) {
return (
<section
data-testid="form-search-mobile-results"
Expand All @@ -420,7 +430,7 @@ function MobileCards({ matches }: { matches: FormSearchMatch[] }) {
className="grid grid-cols-[38px_minmax(0,1fr)] gap-1.5 rounded-lg border border-[color:var(--border)] bg-[color:var(--surface)] p-1 shadow-[0_1px_2px_rgb(12_24_34_/_5%)]"
>
<div className="grid h-9 w-9 place-items-center rounded-lg border border-[color:var(--clinical-accent-border)] bg-[color:var(--clinical-accent-soft)] text-lg font-extrabold leading-none text-[color:var(--clinical-accent)]">
{resultCode(index)}
{resultCode(match, index)}
</div>
<div className="min-w-0">
<div className="flex min-w-0 items-start justify-between gap-2">
Expand Down Expand Up @@ -456,7 +466,7 @@ function MobileCards({ matches }: { matches: FormSearchMatch[] }) {
})}
</div>
<p className="mt-0.5 truncate text-3xs font-medium leading-3 text-[color:var(--text-muted)]">
{compactMatchReason(match)}
{compactMatchReason(match, query)}
</p>
</div>
</article>
Expand Down Expand Up @@ -580,6 +590,7 @@ export function FormsSearchResultsPage(props: FormsSearchResultsPageProps) {
}

function FormsSearchResultsPageContent({ query }: FormsSearchResultsPageProps) {
const router = useRouter();
const command = useSearchCommand();
const registry = useRegistryRecords("form");
const registryReady = registry.status === "ready";
Expand All @@ -604,17 +615,24 @@ function FormsSearchResultsPageContent({ query }: FormsSearchResultsPageProps) {
<SearchResultsHeaderBand modeId="forms" query={query} matchCount={scopedMatches.length} />
</div>
{query.trim() && scopedMatches.length === 0 ? (
<SearchResultsEmptyState modeId="forms" query={query} onClearScopes={command?.onClearScopes} />
<SearchResultsEmptyState
modeId="forms"
query={query}
onClearScopes={command?.onClearScopes}
onTryExample={(example) =>
router.push(appModeHomeHref("forms", { query: example, focus: true, run: true }))
}
/>
) : (
<>
<div className="overflow-x-auto">
<ResultTabs formsCount={scopedMatches.length} />
</div>
<div className="hidden lg:block">
<ResultsTable matches={scopedMatches} />
<ResultsTable matches={scopedMatches} query={query} />
</div>
<div className="lg:hidden">
<MobileCards matches={scopedMatches} />
<MobileCards matches={scopedMatches} query={query} />
</div>
</>
)}
Expand Down
Loading
Loading