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 ffceb8dfe5f..2983488444a 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,10 @@ 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 { useTranslation } from "react-i18next"; +import { useOnInView } from "react-intersection-observer"; function PrescriptionTags({ tags }: { tags?: TagConfig[] }) { if (!tags || tags.length === 0) return null; @@ -47,6 +48,8 @@ interface PrescriptionListSelectorProps { onSelectPrescription: (prescription: PrescritionList | undefined) => void; } +const RESULTS_PER_PAGE_LIMIT = 14; + export default function PrescriptionListSelector({ patientId, encounterId, @@ -56,13 +59,37 @@ 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 { data, isLoading, fetchNextPage, hasNextPage, isFetchingNextPage } = + useInfiniteQuery({ + queryKey: ["infinite-prescriptions", patientId, encounterId, facilityId], + queryFn: async ({ pageParam = 0, signal }) => { + const response = await query(prescriptionApi.list, { + pathParams: { patientId }, + queryParams: { + encounter: encounterId, + facility: facilityId, + limit: String(RESULTS_PER_PAGE_LIMIT), + offset: String(pageParam), + }, + })({ + signal, + }); + return response; + }, + initialPageParam: 0, + getNextPageParam: (lastPage, allPages) => { + const currentOffset = allPages.length * RESULTS_PER_PAGE_LIMIT; + return currentOffset < lastPage.count ? currentOffset : null; + }, + }); + + const prescriptions = data?.pages.flatMap((page) => page.results) ?? []; + + const loadMoreRef = useOnInView((inView) => { + if (inView && hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } }); const handleSelectPrescription = React.useCallback( @@ -82,7 +109,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 +118,11 @@ export default function PrescriptionListSelector({ <>
@@ -154,7 +183,9 @@ export default function PrescriptionListSelector({
@@ -176,10 +207,14 @@ function PrescriptionList({ prescriptions, selectedPrescriptionId, onSelectPrescription, + isFetchingNextPage, + loadMoreRef, }: { prescriptions: PrescritionList[]; selectedPrescriptionId: string | undefined; onSelectPrescription: (prescription: PrescritionList | undefined) => void; + isFetchingNextPage: boolean; + loadMoreRef: React.Ref; }) { const { t } = useTranslation(); @@ -199,7 +234,7 @@ function PrescriptionList({ return (
- {items.map((item) => { + {items.map((item, i) => { const isSelected = selectedPrescriptionId === item.id; return ( @@ -214,6 +249,7 @@ function PrescriptionList({ onClick={() => onSelectPrescription(prescriptions.find((p) => p.id === item.id)) } + ref={i === items.length - 1 ? loadMoreRef : undefined} > {isSelected && (
@@ -240,6 +276,7 @@ function PrescriptionList({ ); })} + {isFetchingNextPage && }
); }