From ff5c0465ad1058be8bbc5d097e15aa81103099d9 Mon Sep 17 00:00:00 2001 From: vasiliki Date: Wed, 27 May 2026 14:09:25 +0100 Subject: [PATCH] add loading transition to concept filtering and try to fix refresh issue --- app/page.tsx | 9 +++---- components/ConceptList.tsx | 45 ++++++++++++++++---------------- components/NoteCard.tsx | 53 +++++++++++++++++++++++++++++++------- lib/helpers.ts | 3 ++- 4 files changed, 71 insertions(+), 39 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 8129740..e4b5042 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -64,15 +64,12 @@ function PageContent({
- Loading concepts...
}> - - - Loading notes...}> - - + + + diff --git a/components/ConceptList.tsx b/components/ConceptList.tsx index c849971..5efdc11 100644 --- a/components/ConceptList.tsx +++ b/components/ConceptList.tsx @@ -4,6 +4,7 @@ import type { Concept } from "@/types/OmopTables"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; +import { buildSearchParams } from "@/lib/helpers"; export default function ConceptList({ concepts }: { concepts: Concept[] }) { const router = useRouter(); @@ -12,34 +13,30 @@ export default function ConceptList({ concepts }: { concepts: Concept[] }) { const selectedConcepts = searchParams.getAll("conceptId").sort(); const onSelect = (conceptId: string) => { - const currentParams = searchParams.getAll("conceptId").sort(); + const current = searchParams.getAll("conceptId"); - let nextConceptIds: string[]; + const nextConceptIds = current.includes(conceptId) + ? current.filter((id) => id !== conceptId) + : [...current, conceptId]; - if (currentParams.includes(conceptId)) { - nextConceptIds = currentParams.filter((id) => id !== conceptId); - } else { - nextConceptIds = [...currentParams, conceptId]; - } - const params = new URLSearchParams(); + const query = buildSearchParams({ + conceptIds: nextConceptIds, + domain: searchParams.get("domain"), + page: 1, + }); - // Keep domain if exists - const domain = searchParams.get("domain"); - if (domain && domain !== "All") { - params.set("domain", domain); - } - - // Add conceptIds to Url - nextConceptIds.sort(); - nextConceptIds.forEach((id) => params.append("conceptId", id)); - - // Reset page number - params.set("page", "1"); - router.replace(`${pathname}?${params.toString()}`, { scroll: false }); + router.replace(`${pathname}?${query}`, { scroll: false }); router.refresh(); }; const clearSelection = () => { - router.replace(pathname); + const query = buildSearchParams({ + conceptIds: [], + domain: searchParams.get("domain"), + page: 1, + }); + + router.replace(`${pathname}?${query}`, { scroll: false }); + }; return ( @@ -62,7 +59,9 @@ export default function ConceptList({ concepts }: { concepts: Concept[] }) { : "ghost" } className={`w-full justify-between h-auto py-3 px-4 ${ - selectedConcepts.includes(c.concept_id) ? "bg-mist-100 dark:bg-neutral-800" : "" + selectedConcepts.includes(c.concept_id) + ? "bg-mist-100 dark:bg-neutral-800" + : "" }`} onClick={() => onSelect(c.concept_id)} > diff --git a/components/NoteCard.tsx b/components/NoteCard.tsx index 1661d3e..4217356 100644 --- a/components/NoteCard.tsx +++ b/components/NoteCard.tsx @@ -19,6 +19,7 @@ import { ChevronDownIcon } from "@radix-ui/react-icons"; import Link from "next/link"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { buildSearchParams } from "@/lib/helpers"; +import { useTransition } from "react"; export default function NoteCard({ note, @@ -31,8 +32,12 @@ export default function NoteCard({ const pathname = usePathname(); const searchParams = useSearchParams(); + const [isPending, startTransition] = useTransition(); + const selectedConceptIds = searchParams.getAll("conceptId"); + const pmcid = note.note_source_value?.match(/PMC(\d+)/)?.[1]; + const uniqueConcepts = Array.from( new Map( (note.concepts || []).map((c: any) => [ @@ -58,12 +63,21 @@ export default function NoteCard({ page: 1, }); - router.push(`${pathname}?${query}`); - router.refresh(); + startTransition(() => { + router.replace(`${pathname}?${query}`, { + scroll: false, + }); + }); }; return ( - + {article?.articleUrl && pmcid ? ( @@ -75,17 +89,29 @@ export default function NoteCard({ {article.title} ) : ( -

Loading article...

+

+ Loading article... +

)}
+ + {isPending && ( +
+ Loading Case Reports... +
+ )}
{article ? ( - @@ -95,39 +121,48 @@ export default function NoteCard({ ) : ( -

Loading article...

+

+ Loading article... +

)}
{uniqueConcepts.map((c: Concept) => { - const selected = selectedConceptIds.includes(String(c.concept_id)); + const selected = selectedConceptIds.includes( + String(c.concept_id), + ); return ( selectConcept(String(c.concept_id))} className={` cursor-pointer transition hover:opacity-80 flex flex-wrap gap-2 py-0 text-sm + ${selected ? "ring-2 ring-primary" : ""} + ${ c.domain === "Condition" ? "bg-sky-100 dark:bg-[#1B3C53]" : "" } + ${ c.domain === "Drug" ? "bg-emerald-100 dark:bg-[#3F4F44]" : "" } + ${ c.domain === "Procedure" ? "bg-violet-100 dark:bg-[#49243E]" : "" } + ${ c.domain === "Measurement" ? "bg-orange-100 dark:bg-amber-800" @@ -143,4 +178,4 @@ export default function NoteCard({ ); -} +} \ No newline at end of file diff --git a/lib/helpers.ts b/lib/helpers.ts index f963913..ce991f1 100644 --- a/lib/helpers.ts +++ b/lib/helpers.ts @@ -16,7 +16,8 @@ export function buildSearchParams({ // Sort and add unique conceptIds [...new Set(conceptIds)] - .sort((a, b) => Number(a) - Number(b)) + .map(String) + .sort() .forEach((id) => params.append("conceptId", id)); // Set page