'use client'; import React, { useEffect, useRef, useState } from 'react'; import { Loader } from 'lucide-react'; import { PDFDocumentProxy } from 'pdfjs-dist'; import { Document as PDFDocument, Page as PDFPage, pdfjs } from 'react-pdf'; import 'react-pdf/dist/esm/Page/AnnotationLayer.css'; import 'react-pdf/dist/esm/Page/TextLayer.css'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { cn } from '@documenso/ui/lib/utils'; export type LoadedPDFDocument = PDFDocumentProxy; /** * This imports the worker from the `pdfjs-dist` package. */ pdfjs.GlobalWorkerOptions.workerSrc = `/pdf.worker.min.js`; export type OnPDFViewerPageClick = (_event: { pageNumber: number; numPages: number; originalEvent: React.MouseEvent; pageHeight: number; pageWidth: number; pageX: number; pageY: number; }) => void | Promise; export type PDFViewerProps = { className?: string; document: string; onDocumentLoad?: (_doc: LoadedPDFDocument) => void; onPageClick?: OnPDFViewerPageClick; [key: string]: unknown; } & Omit, 'onPageClick'>; export const PDFViewer = ({ className, document, onDocumentLoad, onPageClick, ...props }: PDFViewerProps) => { const $el = useRef(null); const [width, setWidth] = useState(0); const [numPages, setNumPages] = useState(0); const [pdfError, setPdfError] = useState(false); const onDocumentLoaded = (doc: LoadedPDFDocument) => { setNumPages(doc.numPages); onDocumentLoad?.(doc); }; const onDocumentPageClick = ( event: React.MouseEvent, pageNumber: number, ) => { const $el = event.target instanceof HTMLElement ? event.target : null; if (!$el) { return; } const $page = $el.closest(PDF_VIEWER_PAGE_SELECTOR); if (!$page) { return; } const { height, width, top, left } = $page.getBoundingClientRect(); const pageX = event.clientX - left; const pageY = event.clientY - top; if (onPageClick) { void onPageClick({ pageNumber, numPages, originalEvent: event, pageHeight: height, pageWidth: width, pageX, pageY, }); } }; useEffect(() => { if ($el.current) { const $current = $el.current; const { width } = $current.getBoundingClientRect(); setWidth(width); const onResize = () => { const { width } = $current.getBoundingClientRect(); setWidth(width); }; window.addEventListener('resize', onResize); return () => { window.removeEventListener('resize', onResize); }; } }, []); return (
onDocumentLoaded(d)} // Uploading a invalid document causes an error which doesn't appear to be handled by the `error` prop. // Therefore we add some additional custom error handling. onSourceError={() => { setPdfError(true); }} externalLinkTarget="_blank" loading={
{pdfError ? (

Something went wrong while loading the document.

Please try again or contact our support.

) : ( <>

Loading document...

)}
} error={

Something went wrong while loading the document.

Please try again or contact our support.

} > {Array(numPages) .fill(null) .map((_, i) => (
''} onClick={(e) => onDocumentPageClick(e, i + 1)} />
))}
); }; export default PDFViewer;