diff --git a/apps/Backend/src/routes/documenets.ts b/apps/Backend/src/routes/documenets.ts index ea4c44b..239f376 100644 --- a/apps/Backend/src/routes/documenets.ts +++ b/apps/Backend/src/routes/documenets.ts @@ -1,8 +1,6 @@ import { Router } from "express"; import { Request, Response } from "express"; import { storage } from "../storage"; -import { z } from "zod"; -import { ClaimUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas"; import multer from "multer"; const upload = multer({ storage: multer.memoryStorage() }); @@ -57,9 +55,17 @@ router.get("/claim-pdf/:id", async (req: Request, res: Response): Promise = const id = parseInt(idParam); const pdf = await storage.getClaimPdfById(id); - if (!pdf) return res.status(404).json({ error: "PDF not found" }); + if (!pdf || !pdf.pdfData) return res.status(404).json({ error: "PDF not found" }); + // Fix bad objectified Buffer + if (!Buffer.isBuffer(pdf.pdfData)) { + pdf.pdfData = Buffer.from(Object.values(pdf.pdfData)); + } res.setHeader("Content-Type", "application/pdf"); + res.setHeader( + "Content-Disposition", + `attachment; filename="${pdf.filename}"; filename*=UTF-8''${encodeURIComponent(pdf.filename)}` +); res.send(pdf.pdfData); } catch (err) { console.error("Error fetching PDF by ID:", err); diff --git a/apps/Backend/src/storage/index.ts b/apps/Backend/src/storage/index.ts index c762ef9..435402e 100644 --- a/apps/Backend/src/storage/index.ts +++ b/apps/Backend/src/storage/index.ts @@ -6,7 +6,7 @@ import { StaffUncheckedCreateInputObjectSchema, ClaimUncheckedCreateInputObjectSchema, InsuranceCredentialUncheckedCreateInputObjectSchema, - ClaimPdfUncheckedCreateInputObjectSchema + ClaimPdfUncheckedCreateInputObjectSchema, } from "@repo/db/usedSchemas"; import { z } from "zod"; @@ -146,7 +146,7 @@ type ClaimWithServiceLines = Claim & { }[]; }; -// claim types: +// claim types: type ClaimPdf = z.infer; export interface ClaimPdfMetadata { @@ -166,6 +166,7 @@ export interface IStorage { // Patient methods getPatient(id: number): Promise; getPatientsByUserId(userId: number): Promise; + getRecentPatients(limit: number, offset: number): Promise; createPatient(patient: InsertPatient): Promise; updatePatient(id: number, patient: UpdatePatient): Promise; deletePatient(id: number): Promise; @@ -175,6 +176,8 @@ export interface IStorage { getAllAppointments(): Promise; getAppointmentsByUserId(userId: number): Promise; getAppointmentsByPatientId(patientId: number): Promise; + getRecentAppointments(limit: number, offset: number): Promise; + getAppointmentsOn(date: Date): Promise; createAppointment(appointment: InsertAppointment): Promise; updateAppointment( id: number, @@ -234,7 +237,10 @@ export interface IStorage { getAllClaimPdfs(): Promise; - getRecentClaimPdfs(limit: number, offset: number): Promise; + getRecentClaimPdfs( + limit: number, + offset: number + ): Promise; deleteClaimPdf(id: number): Promise; @@ -290,6 +296,14 @@ export const storage: IStorage = { return await db.patient.findMany({ where: { userId } }); }, + async getRecentPatients(limit: number, offset: number): Promise { + return db.patient.findMany({ + skip: offset, + take: limit, + orderBy: { createdAt: "desc" }, + }); + }, + async createPatient(patient: InsertPatient): Promise { return await db.patient.create({ data: patient as Patient }); }, @@ -332,6 +346,35 @@ export const storage: IStorage = { return await db.appointment.findMany({ where: { patientId } }); }, + async getAppointmentsOn(date: Date): Promise { + const start = new Date(date); + start.setHours(0, 0, 0, 0); + + const end = new Date(date); + end.setHours(23, 59, 59, 999); + + return db.appointment.findMany({ + where: { + date: { + gte: start, + lte: end, + }, + }, + orderBy: { date: "asc" }, + }); + }, + + async getRecentAppointments( + limit: number, + offset: number + ): Promise { + return db.appointment.findMany({ + skip: offset, + take: limit, + orderBy: { date: "desc" } + }); + }, + async createAppointment( appointment: InsertAppointment ): Promise { @@ -534,7 +577,10 @@ export const storage: IStorage = { }); }, - async getRecentClaimPdfs(limit: number, offset: number): Promise { + async getRecentClaimPdfs( + limit: number, + offset: number + ): Promise { return db.claimPdf.findMany({ skip: offset, take: limit, @@ -543,6 +589,7 @@ export const storage: IStorage = { id: true, filename: true, uploadedAt: true, + patient:true, }, }); }, @@ -561,7 +608,10 @@ export const storage: IStorage = { updates: Partial> ): Promise { try { - const updated = await db.claimPdf.update({ where: { id }, data: updates }); + const updated = await db.claimPdf.update({ + where: { id }, + data: updates, + }); return updated; } catch { return undefined; diff --git a/apps/Frontend/src/pages/documents-page.tsx b/apps/Frontend/src/pages/documents-page.tsx index 11e9b6b..5a81933 100644 --- a/apps/Frontend/src/pages/documents-page.tsx +++ b/apps/Frontend/src/pages/documents-page.tsx @@ -1,19 +1,19 @@ -import { useState } from "react"; -import { useQuery } from "@tanstack/react-query"; +import { useEffect, useState } from "react"; +import { useMutation, useQuery } from "@tanstack/react-query"; import { TopAppBar } from "@/components/layout/top-app-bar"; import { Sidebar } from "@/components/layout/sidebar"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { - Search, - Edit, - Eye, - ChevronLeft, +import { Card, CardContent } from "@/components/ui/card"; +import { + Search, + Eye, + ChevronLeft, ChevronRight, - Settings + Settings, + Trash, + Download, } from "lucide-react"; -import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas"; import { useAuth } from "@/hooks/use-auth"; import { cn } from "@/lib/utils"; import { @@ -23,37 +23,19 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import {z} from "zod"; - - -const PatientSchema = ( - PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject -).omit({ - appointments: true, -}); -type Patient = z.infer; - -const insertPatientSchema = ( - PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject -).omit({ - id: true, - createdAt: true, - userId: true, -}); -type InsertPatient = z.infer; - -const updatePatientSchema = ( - PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject -) - .omit({ - id: true, - createdAt: true, - userId: true, - }) - .partial(); - -type UpdatePatient = z.infer; +import { ClaimPdfUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas"; +import { z } from "zod"; +import "@react-pdf-viewer/core/lib/styles/index.css"; +import "@react-pdf-viewer/default-layout/lib/styles/index.css"; +import { Viewer, Worker } from "@react-pdf-viewer/core"; +import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout"; +import { apiRequest, queryClient } from "@/lib/queryClient"; +import { toast } from "@/hooks/use-toast"; +import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog"; +const ClaimPdfSchema = + ClaimPdfUncheckedCreateInputObjectSchema as unknown as z.ZodObject; +type ClaimPdf = z.infer; export default function DocumentsPage() { const { user } = useAuth(); @@ -62,24 +44,139 @@ export default function DocumentsPage() { const [searchField, setSearchField] = useState("all"); const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 5; + const [selectedPdfId, setSelectedPdfId] = useState(null); + const defaultLayoutPluginInstance = defaultLayoutPlugin(); + const [isDeletePdfOpen, setIsDeletePdfOpen] = useState(false); + const [currentPdf, setCurrentPdf] = useState(null); - // Fetch patients - const { - data: patients = [], - isLoading: isLoadingPatients, - } = useQuery({ - queryKey: ["/api/patients"], + const { data: pdfs = [], isLoading } = useQuery({ + queryKey: ["/api/documents/claim-pdf/recent"], enabled: !!user, + queryFn: async () => { + const res = await apiRequest("GET", "/api/documents/claim-pdf/recent"); + return res.json(); + }, }); - // Filter patients based on search - const filteredPatients = patients.filter(patient => { - if (!searchTerm) return true; - + const deletePdfMutation = useMutation({ + mutationFn: async (id: number) => { + await apiRequest("DELETE", `/api/documents/claim-pdf/${id}`); + }, + onSuccess: () => { + setIsDeletePdfOpen(false); + setCurrentPdf(null); + queryClient.invalidateQueries({ + queryKey: ["/api/documents/claim-pdf/recent"], + }); + + toast({ + title: "Success", + description: "PDF deleted successfully!", + variant: "default", + }); + }, + onError: (error: any) => { + console.error("Error deleting PDF:", error); + toast({ + title: "Error", + description: `Failed to delete PDF: ${error.message || error}`, + variant: "destructive", + }); + }, + }); + + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + }); + }; + + const getPatientInitials = (first: string, last: string) => + `${first[0]}${last[0]}`.toUpperCase(); + + const [fileBlobUrl, setFileBlobUrl] = useState(null); + + useEffect(() => { + if (!selectedPdfId) return; + let url: string | null = null; + + const fetchPdf = async () => { + try { + const res = await apiRequest( + "GET", + `/api/documents/claim-pdf/${selectedPdfId}` + ); + + const arrayBuffer = await res.arrayBuffer(); + const blob = new Blob([arrayBuffer], { type: "application/pdf" }); + const objectUrl = URL.createObjectURL(blob); + setFileBlobUrl(objectUrl); + url = objectUrl; + } catch (err) { + console.error("Failed to load PDF", err); + } + }; + + fetchPdf(); + + return () => { + if (url) { + URL.revokeObjectURL(url); + } + }; + }, [selectedPdfId]); + + const toggleMobileMenu = () => setIsMobileMenuOpen((prev) => !prev); + + const viewPdf = (pdfId: number) => { + setSelectedPdfId(pdfId); + }; + + const downloadPdf = async (pdfId: number, filename: string) => { + try { + const res = await apiRequest("GET", `/api/documents/claim-pdf/${pdfId}`); + const arrayBuffer = await res.arrayBuffer(); + const blob = new Blob([arrayBuffer], { type: "application/pdf" }); + const url = URL.createObjectURL(blob); + + const a = document.createElement("a"); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } catch (err) { + console.error("Failed to download PDF:", err); + } + }; + + const handleDeletePdf = (pdf: ClaimPdf) => { + setCurrentPdf(pdf); + setIsDeletePdfOpen(true); + }; + + const handleConfirmDeletePdf = () => { + if (currentPdf) { + deletePdfMutation.mutate(currentPdf.id); + } else { + toast({ + title: "Error", + description: "No PDF selected for deletion.", + variant: "destructive", + }); + } + }; + + const filteredPdfs = pdfs.filter((pdf) => { + const patient = pdf.patient; const searchLower = searchTerm.toLowerCase(); const fullName = `${patient.firstName} ${patient.lastName}`.toLowerCase(); - const patientId = `PID-${patient.id.toString().padStart(4, '0')}`; - + const patientId = `PID-${patient.id.toString().padStart(4, "0")}`; + switch (searchField) { case "name": return fullName.includes(searchLower); @@ -91,7 +188,7 @@ export default function DocumentsPage() { default: return ( fullName.includes(searchLower) || - patientId.toLowerCase().includes(searchLower) || + patientId.includes(searchLower) || patient.phone?.toLowerCase().includes(searchLower) || patient.email?.toLowerCase().includes(searchLower) || false @@ -99,45 +196,31 @@ export default function DocumentsPage() { } }); - // Pagination - const totalPages = Math.ceil(filteredPatients.length / itemsPerPage); + const totalPages = Math.ceil(filteredPdfs.length / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; - const endIndex = startIndex + itemsPerPage; - const currentPatients = filteredPatients.slice(startIndex, endIndex); - - const toggleMobileMenu = () => { - setIsMobileMenuOpen(!isMobileMenuOpen); - }; - - const formatDate = (dateString: string) => { - const date = new Date(dateString); - return date.toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric' - }); - }; - - const getPatientInitials = (firstName: string, lastName: string) => { - return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase(); - }; + const currentPdfs = filteredPdfs.slice(startIndex, startIndex + itemsPerPage); return (
- - + +
- +
- {/* Header */}
-

Documents

-

View and manage all patient information

+

+ Documents +

+

+ View and manage recent uploaded claim PDFs +

- {/* Search and Filters */}
@@ -171,14 +254,18 @@ export default function DocumentsPage() { - {/* Patient List */} - {isLoadingPatients ? ( -
Loading patients...
+ {isLoading ? ( +
Loading data...
+ ) : currentPdfs.length === 0 ? ( +
+ {searchTerm + ? "No results matching your search." + : "No recent claim PDFs available."} +
) : ( <> - {/* Table Header */}
Patient
DOB / Gender
@@ -188,33 +275,30 @@ export default function DocumentsPage() {
Actions
- {/* Table Rows */} - {currentPatients.length === 0 ? ( -
- {searchTerm ? "No patients found matching your search." : "No patients available."} -
- ) : ( - currentPatients.map((patient) => ( -
{ + const patient = pdf.patient; + return ( +
- {/* Patient Info */}
- {getPatientInitials(patient.firstName, patient.lastName)} + {getPatientInitials( + patient.firstName, + patient.lastName + )}
{patient.firstName} {patient.lastName}
- PID-{patient.id.toString().padStart(4, '0')} + PID-{patient.id.toString().padStart(4, "0")}
- {/* DOB / Gender */}
{formatDate(patient.dateOfBirth)} @@ -224,78 +308,141 @@ export default function DocumentsPage() {
- {/* Contact */}
- {patient.phone || 'Not provided'} + {patient.phone || "Not provided"}
- {patient.email || 'No email'} + {patient.email || "No email"}
- {/* Insurance */}
- {patient.insuranceProvider ? - `${patient.insuranceProvider.charAt(0).toUpperCase()}${patient.insuranceProvider.slice(1)}` : - 'Not specified' - } + {patient.insuranceProvider + ? `${patient.insuranceProvider.charAt(0).toUpperCase()}${patient.insuranceProvider.slice(1)}` + : "Not specified"}
- ID: {patient.insuranceId || 'N/A'} + ID: {patient.insuranceId || "N/A"}
- {/* Status */}
- - {patient.status === 'active' ? 'Active' : 'Inactive'} + + {patient.status === "active" + ? "Active" + : "Inactive"}
- {/* Actions */}
- - +
- )) + ); + })} + + setIsDeletePdfOpen(false)} + entityName={`PDF #${currentPdf?.id}`} + /> + + {/* PDF Viewer */} + {selectedPdfId && fileBlobUrl && ( +
+
+

+ Viewing PDF #{selectedPdfId} +

+ +
+
+ + + +
+
)} {/* Pagination */} {totalPages > 1 && (
- Showing {startIndex + 1} to {Math.min(endIndex, filteredPatients.length)} of {filteredPatients.length} results + Showing {startIndex + 1} to{" "} + {Math.min( + startIndex + itemsPerPage, + filteredPdfs.length + )}{" "} + of {filteredPdfs.length} results
- - {/* Page Numbers */} - {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => ( + {Array.from( + { length: totalPages }, + (_, i) => i + 1 + ).map((page) => ( ))} -
); -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 966e785..2a1c324 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,8 +13,11 @@ "packages/*" ], "dependencies": { + "@react-pdf-viewer/core": "^3.12.0", + "@react-pdf-viewer/default-layout": "^3.12.0", "dotenv": "^16.5.0", "dotenv-cli": "^8.0.0", + "pdfjs-dist": "^3.11.174", "shx": "^0.4.0" }, "devDependencies": { @@ -3293,6 +3296,254 @@ "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==", "license": "MIT" }, + "node_modules/@react-pdf-viewer/attachment": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/attachment/-/attachment-3.12.0.tgz", + "integrity": "sha512-mhwrYJSIpCvHdERpLUotqhMgSjhtF+BTY1Yb9Fnzpcq3gLZP+Twp5Rynq21tCrVdDizPaVY7SKu400GkgdMfZw==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/bookmark": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/bookmark/-/bookmark-3.12.0.tgz", + "integrity": "sha512-i7nEit8vIFMAES8RFGwprZ9cXOOZb9ZStPW6E6yuObJEXcvBj/ctsbBJGZxqUZOGklM0JoB7sjHyxAriHfe92A==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/core": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/core/-/core-3.12.0.tgz", + "integrity": "sha512-8MsdlQJ4jaw3GT+zpCHS33nwnvzpY0ED6DEahZg9WngG++A5RMhk8LSlxdHelwaFFHFiXBjmOaj2Kpxh50VQRg==", + "license": "https://react-pdf-viewer.dev/license", + "peerDependencies": { + "pdfjs-dist": "^2.16.105 || ^3.0.279", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/default-layout": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/default-layout/-/default-layout-3.12.0.tgz", + "integrity": "sha512-K2fS4+TJynHxxCBFuIDiFuAw3nqOh4bkBgtVZ/2pGvnFn9lLg46YGLMnTXCQqtyZzzXYh696jmlFViun3is4pA==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/attachment": "3.12.0", + "@react-pdf-viewer/bookmark": "3.12.0", + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/thumbnail": "3.12.0", + "@react-pdf-viewer/toolbar": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/full-screen": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/full-screen/-/full-screen-3.12.0.tgz", + "integrity": "sha512-hQouJ26QUaRBCXNMU1aI1zpJn4l4PJRvlHhuE2dZYtLl37ycjl7vBCQYZW1FwnuxMWztZsY47R43DKaZORg0pg==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/get-file": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/get-file/-/get-file-3.12.0.tgz", + "integrity": "sha512-Uhq45n2RWlZ7Ec/BtBJ0WQESRciaYIltveDXHNdWvXgFdOS8XsvB+mnTh/wzm7Cfl9hpPyzfeezifdU9AkQgQg==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/open": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/open/-/open-3.12.0.tgz", + "integrity": "sha512-vhiDEYsiQLxvZkIKT9VPYHZ1BOnv46x9eCEmRWxO1DJ8fa/GRDTA9ivXmq/ap0dGEJs6t+epleCkCEfllLR/Yw==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/page-navigation": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/page-navigation/-/page-navigation-3.12.0.tgz", + "integrity": "sha512-tVEJ48Dd5kajV1nKkrPWijglJRNBiKBTyYDKVexhiRdTHUP1f6QQXiSyDgCUb0IGSZeJzOJb1h7ApKHe8OTtuw==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/print": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/print/-/print-3.12.0.tgz", + "integrity": "sha512-xJn76CgbU/M2iNaN7wLHTg+sdOekkRMfCakFLwPrE+SR7qD6NUF4vQQKJBSVCCK5bUijzb6cWfKGfo8VA72o4Q==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/properties": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/properties/-/properties-3.12.0.tgz", + "integrity": "sha512-dYTCHtVwFNkpDo7QxL2qk/8zAKndLwdD1FFxBftl6jIlQbtvNdxkFfkv1HcQING9Ic+7DBryOiD7W0ze4IERYg==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/rotate": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/rotate/-/rotate-3.12.0.tgz", + "integrity": "sha512-yaxaMYPChvNOjR8+AxRmj0kvojyJKPq4XHEcIB2lJJgBY1Zra3mliDUP3Nlb4yV8BS9+yBqWn9U9mtnopQD+tw==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/scroll-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/scroll-mode/-/scroll-mode-3.12.0.tgz", + "integrity": "sha512-okII7Xqhl6cMvl1izdEvlXNJ+vJVq/qdg53hJIDYVgBCWskLk/cpjUg/ZonBxseG9lIDP3w2VO1McT8Gn11OAg==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/search": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/search/-/search-3.12.0.tgz", + "integrity": "sha512-jAkLpis49fsDDY/HrbUZIOIhzF5vynONQNA4INQKI38r/MjveblrkNv7qbr9j5lQ/WFic5+gD1e+Mtpf1/7DiA==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/selection-mode": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/selection-mode/-/selection-mode-3.12.0.tgz", + "integrity": "sha512-yysWEu2aCtBvzSgbhgI9kT5cq2hf0FU6Z+3B7MMXz14Kxyc3y18wUqxtgbvpFEfWF0bNUUq16JtWRljtxvZ83w==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/theme": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/theme/-/theme-3.12.0.tgz", + "integrity": "sha512-cdBi+wR1VOZ6URCcO9plmAZQu4ZGFcd7HJdBe7VIFiGyrvl9I/Of74ONLycnDImSuONt8D3uNjPBLieeaShVeg==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/thumbnail": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/thumbnail/-/thumbnail-3.12.0.tgz", + "integrity": "sha512-Vc8j3bO6wumWZV4o6pAbktPWKDSC9tQAzOCJ3cof541u4i44C11ccYC4W9aNcsMMUSO3bNwAGWtP8OFthV5akQ==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/toolbar": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/toolbar/-/toolbar-3.12.0.tgz", + "integrity": "sha512-qACTU3qXHgtNK8J+T13EWio+0liilj86SJ87BdapqXynhl720OKPlSKOQqskUGqg3oTUJAhrse9XG6SFdHJx+g==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0", + "@react-pdf-viewer/full-screen": "3.12.0", + "@react-pdf-viewer/get-file": "3.12.0", + "@react-pdf-viewer/open": "3.12.0", + "@react-pdf-viewer/page-navigation": "3.12.0", + "@react-pdf-viewer/print": "3.12.0", + "@react-pdf-viewer/properties": "3.12.0", + "@react-pdf-viewer/rotate": "3.12.0", + "@react-pdf-viewer/scroll-mode": "3.12.0", + "@react-pdf-viewer/search": "3.12.0", + "@react-pdf-viewer/selection-mode": "3.12.0", + "@react-pdf-viewer/theme": "3.12.0", + "@react-pdf-viewer/zoom": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@react-pdf-viewer/zoom": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@react-pdf-viewer/zoom/-/zoom-3.12.0.tgz", + "integrity": "sha512-V0GUTyPM77+LzhoKX+T3XI10/HfGdqRTbgeP7ID60FCzcwu6kXWqJn5tzabjDKLTlFv8mJmn0aa/ppkIU97nfA==", + "license": "https://react-pdf-viewer.dev/license", + "dependencies": { + "@react-pdf-viewer/core": "3.12.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@replit/vite-plugin-shadcn-theme-json": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@replit/vite-plugin-shadcn-theme-json/-/vite-plugin-shadcn-theme-json-0.0.4.tgz", @@ -5290,6 +5541,22 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5879,6 +6146,19 @@ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dedent": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", @@ -8587,6 +8867,19 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -8706,6 +8999,13 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", + "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -9315,11 +9615,34 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/pdfjs-dist": { + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" + } + }, "node_modules/pdfservice": { "resolved": "apps/PdfService", "link": true @@ -10940,6 +11263,39 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", diff --git a/package.json b/package.json index 339f2f3..aa5325b 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,11 @@ "packages/*" ], "dependencies": { + "@react-pdf-viewer/core": "^3.12.0", + "@react-pdf-viewer/default-layout": "^3.12.0", "dotenv": "^16.5.0", "dotenv-cli": "^8.0.0", + "pdfjs-dist": "^3.11.174", "shx": "^0.4.0" } }