import React, { useCallback, useEffect, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@/lib/queryClient"; import type { PatientBalanceRow } from "@repo/db/types"; import PatientsBalancesList from "./patients-balances-list"; import ExportReportButton from "./export-button"; type Resp = { balances: PatientBalanceRow[]; totalCount?: number; // optional nextCursor?: string | null; hasMore?: boolean; }; export default function PatientsWithBalanceReport({ startDate, endDate, npiProviderId, }: { startDate: string; endDate: string; npiProviderId?: number | null; }) { const balancesPerPage = 10; const [cursorStack, setCursorStack] = useState<(string | null)[]>([null]); const [cursorIndex, setCursorIndex] = useState(0); const currentCursor = cursorStack[cursorIndex] ?? null; const pageIndex = cursorIndex + 1; // 1-based for UI const { data, isLoading, isError, refetch } = useQuery({ queryKey: [ "/api/payments-reports/patient-balances", currentCursor, balancesPerPage, startDate, endDate, npiProviderId ?? "all", ], queryFn: async () => { const params = new URLSearchParams(); params.set("limit", String(balancesPerPage)); if (currentCursor) params.set("cursor", currentCursor); if (startDate) params.set("from", startDate); if (endDate) params.set("to", endDate); if (npiProviderId) params.set("npiProviderId", String(npiProviderId)); const res = await apiRequest( "GET", `/api/payments-reports/patients-with-balances?${params.toString()}` ); if (!res.ok) { const body = await res .json() .catch(() => ({ message: "Failed to load patient balances" })); throw new Error(body.message || "Failed to load patient balances"); } return res.json(); }, enabled: true, }); const balances = data?.balances ?? []; const totalCount = data?.totalCount ?? undefined; const nextCursor = data?.nextCursor ?? null; const hasMore = data?.hasMore ?? false; useEffect(() => { setCursorStack([null]); setCursorIndex(0); refetch(); }, [startDate, endDate, npiProviderId]); const handleNext = useCallback(() => { const idx = cursorIndex; const isLastKnown = idx === cursorStack.length - 1; if (isLastKnown) { if (nextCursor) { setCursorStack((s) => [...s, nextCursor]); setCursorIndex((i) => i + 1); } } else { setCursorIndex((i) => i + 1); } }, [cursorIndex, cursorStack.length, nextCursor]); const handlePrev = useCallback(() => { setCursorIndex((i) => Math.max(0, i - 1)); }, []); const normalized = balances.map((b) => { const currentBalance = Number(b.currentBalance ?? 0); const totalCharges = Number(b.totalCharges ?? 0); const totalPayments = b.totalPayments != null ? Number(b.totalPayments) : Number(totalCharges - currentBalance); return { id: b.patientId, name: `${b.firstName ?? "Unknown"} ${b.lastName ?? ""}`.trim(), currentBalance, totalCharges, totalPayments, }; }); return (
0} hasNext={hasMore} headerRight={ } />
); }