feat: save insurance PDFs (eligibility/claims/preauth) to Cloud Storage instead of Postgres blobs

New saves go into the patient's Cloud Storage folder under category subfolders
(Eligibility/Claims/PreAuth/Claim Status/Attachments) via a new
storage.savePdfToCloudStorage helper, instead of the legacy PdfGroup/PdfFile
Postgres blob tables. Old records and their read paths are left untouched for
backward compatibility; PDF list/content/delete endpoints and viewers now
transparently handle both legacy numeric ids and new "cloud:<id>" ids.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 00:20:37 -04:00
co-authored by Claude Sonnet 5
parent 1190bc0494
commit 99cdfa702a
36 changed files with 496 additions and 296 deletions
+14 -8
View File
@@ -15,7 +15,13 @@ import { Eye, Trash, Download, FolderOpen, FileText, HardDrive } from "lucide-re
import { useAuth } from "@/hooks/use-auth";
import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog";
import { PatientTable } from "@/components/patients/patient-table";
import { Patient, PdfFile } from "@repo/db/types";
import { Patient, PdfFile as PrismaPdfFile } from "@repo/db/types";
// A PDF list item as returned by /api/documents/pdf-files/group/:groupId and
// /api/documents/recent-pdf-files/group/:groupId — id is a plain number for
// legacy (Postgres-blob) records, or a "cloud:<id>" string for records saved
// to the new Cloud Storage backend.
type PdfFile = Omit<PrismaPdfFile, "id"> & { id: number | string };
import {
Pagination,
PaginationContent,
@@ -50,7 +56,7 @@ export default function DocumentsPage() {
const [showPatientDocuments, setShowPatientDocuments] = useState(false);
// Document preview state
const [previewDocumentId, setPreviewDocumentId] = useState<number | null>(null);
const [previewDocumentId, setPreviewDocumentId] = useState<number | string | null>(null);
const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false);
// Delete document state
@@ -245,7 +251,7 @@ export default function DocumentsPage() {
// DELETE mutation
const deletePdfMutation = useMutation({
mutationFn: async (id: number) => {
mutationFn: async (id: number | string) => {
await apiRequest("DELETE", `/api/documents/pdf-files/${id}`);
},
onSuccess: () => {
@@ -267,7 +273,7 @@ export default function DocumentsPage() {
const handleConfirmDeletePdf = () => {
if (currentPdf) {
deletePdfMutation.mutate(Number(currentPdf.id));
deletePdfMutation.mutate(currentPdf.id);
} else {
toast({
title: "Error",
@@ -277,12 +283,12 @@ export default function DocumentsPage() {
}
};
const handleViewPdf = (pdfId: number, filename?: string) => {
const handleViewPdf = (pdfId: number | string, filename?: string) => {
setPreviewDocumentId(pdfId);
setIsPreviewModalOpen(true);
};
const handleDownloadPdf = async (pdfId: number, filename: string) => {
const handleDownloadPdf = async (pdfId: number | string, filename: string) => {
const res = await apiRequest("GET", `/api/documents/pdf-files/${pdfId}`);
const arrayBuffer = await res.arrayBuffer();
const blob = new Blob([arrayBuffer], { type: "application/pdf" });
@@ -447,7 +453,7 @@ export default function DocumentsPage() {
size="sm"
onClick={() =>
handleViewPdf(
Number(pdf.id),
pdf.id,
pdf.filename
)
}
@@ -459,7 +465,7 @@ export default function DocumentsPage() {
size="sm"
onClick={() =>
handleDownloadPdf(
Number(pdf.id),
pdf.id,
pdf.filename
)
}