From 778d838c28cc07d16294ab7470c1930faf073d44 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Tue, 2 Jun 2026 15:43:09 +0530 Subject: [PATCH 1/8] ENG-405 Add infinite pagination for prescription list in encounter --- .../Medicine/PrescriptionListSelector.tsx | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index ffceb8dfe5f..604cf8ffc24 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -1,5 +1,4 @@ import { cn } from "@/lib/utils"; -import { useQuery } from "@tanstack/react-query"; import * as React from "react"; import { CardListSkeleton } from "@/components/Common/SkeletonLoading"; @@ -18,8 +17,11 @@ import prescriptionApi from "@/types/emr/prescription/prescriptionApi"; import { TagConfig } from "@/types/emr/tagConfig/tagConfig"; import query from "@/Utils/request/query"; import { formatDateTime, formatName } from "@/Utils/utils"; +import { useInfiniteQuery } from "@tanstack/react-query"; import { ChevronDown, ReceiptTextIcon } from "lucide-react"; +import { useEffect } from "react"; import { useTranslation } from "react-i18next"; +import { useInView } from "react-intersection-observer"; function PrescriptionTags({ tags }: { tags?: TagConfig[] }) { if (!tags || tags.length === 0) return null; @@ -56,14 +58,35 @@ export default function PrescriptionListSelector({ }: PrescriptionListSelectorProps) { const { t } = useTranslation(); const [openDrawer, setOpenDrawer] = React.useState(false); - const { data: prescriptions, isLoading } = useQuery({ - queryKey: ["prescriptions", patientId, encounterId], - queryFn: query(prescriptionApi.list, { - pathParams: { patientId }, - queryParams: { encounter: encounterId, facility: facilityId }, - }), - enabled: !!patientId && !!encounterId, - }); + const { ref, inView } = useInView(); + const PAGE_LIMIT = 14; + + const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = + useInfiniteQuery({ + queryKey: ["infinite-prescriptions", patientId, encounterId], + queryFn: async ({ pageParam = 0, signal }) => { + const response = await query(prescriptionApi.list, { + pathParams: { patientId }, + queryParams: { + encounter: encounterId, + facility: facilityId, + limit: String(PAGE_LIMIT), + offset: String(pageParam), + }, + })({ + signal, + }); + return response; + }, + enabled: !!patientId && !!encounterId, + initialPageParam: 0, + getNextPageParam: (lastPage, allPages) => { + const currentOffset = allPages.length * PAGE_LIMIT; + return currentOffset < lastPage.count ? currentOffset : null; + }, + }); + + const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; const handleSelectPrescription = React.useCallback( (prescription: PrescritionList | undefined) => { @@ -73,6 +96,12 @@ export default function PrescriptionListSelector({ [onSelectPrescription], ); + useEffect(() => { + if (inView && hasNextPage) { + fetchNextPage(); + } + }, [inView, hasNextPage, fetchNextPage]); + if (isLoading) { return (
@@ -82,7 +111,7 @@ export default function PrescriptionListSelector({ } const selectedPrescription = selectedPrescriptionId - ? prescriptions?.results.find((pres) => pres.id === selectedPrescriptionId) + ? prescriptions.find((pres) => pres.id === selectedPrescriptionId) : undefined; const isAllSelected = selectedPrescriptionId === undefined; @@ -91,9 +120,11 @@ export default function PrescriptionListSelector({ <>
@@ -154,7 +185,9 @@ export default function PrescriptionListSelector({
@@ -176,10 +209,14 @@ function PrescriptionList({ prescriptions, selectedPrescriptionId, onSelectPrescription, + isFetchingNextPage, + ref, }: { prescriptions: PrescritionList[]; selectedPrescriptionId: string | undefined; onSelectPrescription: (prescription: PrescritionList | undefined) => void; + isFetchingNextPage: boolean; + ref: (node?: Element | null) => void; }) { const { t } = useTranslation(); @@ -199,7 +236,7 @@ function PrescriptionList({ return (
- {items.map((item) => { + {items.map((item, i) => { const isSelected = selectedPrescriptionId === item.id; return ( @@ -214,6 +251,7 @@ function PrescriptionList({ onClick={() => onSelectPrescription(prescriptions.find((p) => p.id === item.id)) } + ref={i === items.length - 1 ? ref : undefined} > {isSelected && (
@@ -240,6 +278,7 @@ function PrescriptionList({ ); })} + {isFetchingNextPage && }
); } From 096af97409bf48dd05caca235c6e316236891077 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Tue, 2 Jun 2026 16:09:29 +0530 Subject: [PATCH 2/8] added greptile suggestions --- src/components/Medicine/PrescriptionListSelector.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index 604cf8ffc24..d0a020ca898 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -49,6 +49,8 @@ interface PrescriptionListSelectorProps { onSelectPrescription: (prescription: PrescritionList | undefined) => void; } +const PAGE_LIMIT = 14; + export default function PrescriptionListSelector({ patientId, encounterId, @@ -59,11 +61,10 @@ export default function PrescriptionListSelector({ const { t } = useTranslation(); const [openDrawer, setOpenDrawer] = React.useState(false); const { ref, inView } = useInView(); - const PAGE_LIMIT = 14; const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ - queryKey: ["infinite-prescriptions", patientId, encounterId], + queryKey: ["infinite-prescriptions", patientId, encounterId, facilityId], queryFn: async ({ pageParam = 0, signal }) => { const response = await query(prescriptionApi.list, { pathParams: { patientId }, From 7e716f96a9258bc0624602ee570e81b2c25604da Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Fri, 5 Jun 2026 13:16:20 +0530 Subject: [PATCH 3/8] used useOnInView --- package-lock.json | 8 +++---- package.json | 2 +- .../Medicine/PrescriptionListSelector.tsx | 22 +++++++++---------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fee2c54a0e..d8d1c938d75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,7 +84,7 @@ "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.55.0", "react-i18next": "^15.2.0", - "react-intersection-observer": "^9.15.1", + "react-intersection-observer": "^10.0.3", "react-pdf": "^9.2.1", "react-phone-number-input": "^3.4.12", "react-resizable-panels": "^3.0.2", @@ -15624,9 +15624,9 @@ } }, "node_modules/react-intersection-observer": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz", - "integrity": "sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-10.0.3.tgz", + "integrity": "sha512-luICLMbs0zxTO/70Zy7K5jOXkABPEVSAF8T3FdZUlctsrIaPLmx8TZe2SSA+CY2HGWfz2INyNTnp82pxNNsShA==", "license": "MIT", "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", diff --git a/package.json b/package.json index e8cfe9f224d..3b112c67511 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.55.0", "react-i18next": "^15.2.0", - "react-intersection-observer": "^9.15.1", + "react-intersection-observer": "^10.0.3", "react-pdf": "^9.2.1", "react-phone-number-input": "^3.4.12", "react-resizable-panels": "^3.0.2", diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index d0a020ca898..97fbf6bbb74 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -19,9 +19,8 @@ import query from "@/Utils/request/query"; import { formatDateTime, formatName } from "@/Utils/utils"; import { useInfiniteQuery } from "@tanstack/react-query"; import { ChevronDown, ReceiptTextIcon } from "lucide-react"; -import { useEffect } from "react"; import { useTranslation } from "react-i18next"; -import { useInView } from "react-intersection-observer"; +import { useOnInView } from "react-intersection-observer"; function PrescriptionTags({ tags }: { tags?: TagConfig[] }) { if (!tags || tags.length === 0) return null; @@ -60,7 +59,6 @@ export default function PrescriptionListSelector({ }: PrescriptionListSelectorProps) { const { t } = useTranslation(); const [openDrawer, setOpenDrawer] = React.useState(false); - const { ref, inView } = useInView(); const { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ @@ -89,6 +87,12 @@ export default function PrescriptionListSelector({ const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; + const loadMoreRef = useOnInView((inView) => { + if (inView && hasNextPage) { + fetchNextPage(); + } + }); + const handleSelectPrescription = React.useCallback( (prescription: PrescritionList | undefined) => { onSelectPrescription(prescription); @@ -97,12 +101,6 @@ export default function PrescriptionListSelector({ [onSelectPrescription], ); - useEffect(() => { - if (inView && hasNextPage) { - fetchNextPage(); - } - }, [inView, hasNextPage, fetchNextPage]); - if (isLoading) { return (
@@ -124,7 +122,7 @@ export default function PrescriptionListSelector({ prescriptions={prescriptions} selectedPrescriptionId={selectedPrescriptionId} onSelectPrescription={onSelectPrescription} - ref={ref} + ref={loadMoreRef} isFetchingNextPage={isFetchingNextPage} />
@@ -186,7 +184,7 @@ export default function PrescriptionListSelector({
void; isFetchingNextPage: boolean; - ref: (node?: Element | null) => void; + ref: React.Ref; }) { const { t } = useTranslation(); From e72283d20f270dfd9093dc2ef0f4654d4173bb74 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Tue, 16 Jun 2026 13:00:52 +0530 Subject: [PATCH 4/8] fetch next page while !isFetchingNextPage --- src/components/Medicine/PrescriptionListSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index 97fbf6bbb74..dbe97463a44 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -88,7 +88,7 @@ export default function PrescriptionListSelector({ const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; const loadMoreRef = useOnInView((inView) => { - if (inView && hasNextPage) { + if (inView && hasNextPage && !isFetchingNextPage) { fetchNextPage(); } }); From 1e5428533624ef01841f03e346592b7b7fd02cd9 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Thu, 18 Jun 2026 16:45:23 +0530 Subject: [PATCH 5/8] update the constant name --- src/components/Medicine/PrescriptionListSelector.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index dbe97463a44..44a9440d920 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -48,7 +48,7 @@ interface PrescriptionListSelectorProps { onSelectPrescription: (prescription: PrescritionList | undefined) => void; } -const PAGE_LIMIT = 14; +const RESULTS_PER_PAGE_LIMIT = 14; export default function PrescriptionListSelector({ patientId, @@ -69,7 +69,7 @@ export default function PrescriptionListSelector({ queryParams: { encounter: encounterId, facility: facilityId, - limit: String(PAGE_LIMIT), + limit: String(RESULTS_PER_PAGE_LIMIT), offset: String(pageParam), }, })({ @@ -80,7 +80,7 @@ export default function PrescriptionListSelector({ enabled: !!patientId && !!encounterId, initialPageParam: 0, getNextPageParam: (lastPage, allPages) => { - const currentOffset = allPages.length * PAGE_LIMIT; + const currentOffset = allPages.length * RESULTS_PER_PAGE_LIMIT; return currentOffset < lastPage.count ? currentOffset : null; }, }); @@ -88,6 +88,7 @@ export default function PrescriptionListSelector({ const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; const loadMoreRef = useOnInView((inView) => { + console.log("In view:", inView); if (inView && hasNextPage && !isFetchingNextPage) { fetchNextPage(); } From 533354a615f2c5f78130eee1575e1be1d47d3d0d Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Wed, 24 Jun 2026 14:31:21 +0530 Subject: [PATCH 6/8] removed console --- src/components/Medicine/PrescriptionListSelector.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index 44a9440d920..f47b7008b42 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -88,7 +88,6 @@ export default function PrescriptionListSelector({ const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; const loadMoreRef = useOnInView((inView) => { - console.log("In view:", inView); if (inView && hasNextPage && !isFetchingNextPage) { fetchNextPage(); } From d0a9ec36fffad5178a6b100f204a3b3d6a91eb53 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Wed, 24 Jun 2026 14:54:36 +0530 Subject: [PATCH 7/8] cleanups --- src/components/Medicine/PrescriptionListSelector.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index f47b7008b42..adf2e731604 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -77,7 +77,6 @@ export default function PrescriptionListSelector({ }); return response; }, - enabled: !!patientId && !!encounterId, initialPageParam: 0, getNextPageParam: (lastPage, allPages) => { const currentOffset = allPages.length * RESULTS_PER_PAGE_LIMIT; From 1c3002602f10ecccdfbc2a00000ca6ba465a29e4 Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Wed, 24 Jun 2026 15:00:28 +0530 Subject: [PATCH 8/8] rename prop name --- src/components/Medicine/PrescriptionListSelector.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Medicine/PrescriptionListSelector.tsx b/src/components/Medicine/PrescriptionListSelector.tsx index adf2e731604..2983488444a 100644 --- a/src/components/Medicine/PrescriptionListSelector.tsx +++ b/src/components/Medicine/PrescriptionListSelector.tsx @@ -121,7 +121,7 @@ export default function PrescriptionListSelector({ prescriptions={prescriptions} selectedPrescriptionId={selectedPrescriptionId} onSelectPrescription={onSelectPrescription} - ref={loadMoreRef} + loadMoreRef={loadMoreRef} isFetchingNextPage={isFetchingNextPage} />
@@ -183,7 +183,7 @@ export default function PrescriptionListSelector({
void; isFetchingNextPage: boolean; - ref: React.Ref; + loadMoreRef: React.Ref; }) { const { t } = useTranslation(); @@ -249,7 +249,7 @@ function PrescriptionList({ onClick={() => onSelectPrescription(prescriptions.find((p) => p.id === item.id)) } - ref={i === items.length - 1 ? ref : undefined} + ref={i === items.length - 1 ? loadMoreRef : undefined} > {isSelected && (