fix: wait for table rows before extracting eligibility data; add batch claim PDF download

This commit is contained in:
Gitead
2026-04-30 15:38:29 -04:00
parent d8f852741a
commit 763a322e79
4 changed files with 182 additions and 4 deletions

View File

@@ -25,6 +25,7 @@ import {
FileCheck,
LoaderCircleIcon,
Stethoscope,
Download,
} from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { Calendar } from "@/components/ui/calendar";
@@ -154,6 +155,8 @@ export default function AppointmentsPage() {
const [selectedClaimColumns, setSelectedClaimColumns] = useState<Set<number>>(new Set());
const [isClaimingColumn, setIsClaimingColumn] = useState(false);
const [selectedReminderColumns, setSelectedReminderColumns] = useState<Set<number>>(new Set());
const [selectedDownloadPdfColumns, setSelectedDownloadPdfColumns] = useState<Set<number>>(new Set());
const [isDownloadingClaimPdfs, setIsDownloadingClaimPdfs] = useState(false);
const toggleReminderColumn = (staffId: number) => {
setSelectedReminderColumns((prev) => {
@@ -173,6 +176,15 @@ export default function AppointmentsPage() {
});
};
const toggleDownloadPdfColumn = (staffId: number) => {
setSelectedDownloadPdfColumns((prev) => {
const next = new Set(prev);
if (next.has(staffId)) next.delete(staffId);
else next.add(staffId);
return next;
});
};
const [, setLocation] = useLocation();
// Select Procedures modal state (opened inline, no navigation)
@@ -1037,6 +1049,38 @@ export default function AppointmentsPage() {
}
};
const handleDownloadClaimPdfs = async () => {
if (!user || selectedDownloadPdfColumns.size === 0) return;
const staffIdsParam = Array.from(selectedDownloadPdfColumns).join(",");
setIsDownloadingClaimPdfs(true);
try {
const res = await apiRequest(
"GET",
`/api/claims/batch-pdf?date=${formattedSelectedDate}&staffIds=${staffIdsParam}`
);
if (!res.ok) {
let errMsg = `Server error ${res.status}`;
try { const body = await res.json(); errMsg = body?.error ?? errMsg; } catch { /* ignore */ }
toast({ title: "Download failed", description: errMsg, variant: "destructive" });
return;
}
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `claims_${formattedSelectedDate}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast({ title: "Download started", description: `Claim PDFs for ${formattedSelectedDate} saved to your Downloads folder.` });
} catch (err: any) {
toast({ title: "Download failed", description: err?.message ?? String(err), variant: "destructive" });
} finally {
setIsDownloadingClaimPdfs(false);
}
};
return (
<div>
<SeleniumTaskBanner
@@ -1174,6 +1218,43 @@ export default function AppointmentsPage() {
</label>
))}
</div>
{/* Download Claim PDF for Column section */}
<div className="flex items-center gap-2 border rounded-md px-3 py-2 bg-white shadow-sm">
<Button
onClick={() => handleDownloadClaimPdfs()}
disabled={isLoading || isDownloadingClaimPdfs || selectedDownloadPdfColumns.size === 0}
size="sm"
>
{isDownloadingClaimPdfs ? (
<>
<LoaderCircleIcon className="h-4 w-4 mr-1 animate-spin" />
Downloading...
</>
) : (
<>
<Download className="h-4 w-4 mr-1" />
Download Claim PDF for Column
</>
)}
</Button>
{staffMembers.map((staff, index) => (
<label
key={staff.id}
className="flex items-center gap-1 cursor-pointer select-none"
>
<input
type="checkbox"
className="w-4 h-4 rounded border-gray-400 accent-teal-600"
checked={selectedDownloadPdfColumns.has(Number(staff.id))}
onChange={() => toggleDownloadPdfColumn(Number(staff.id))}
/>
<span className="text-sm font-medium">
{String.fromCharCode(65 + index)}
</span>
</label>
))}
</div>
</div>
</div>