import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import type { MessageDescriptor } from '@lingui/core'; import { msg } from '@lingui/core/macro'; import { Trans, useLingui } from '@lingui/react/macro'; import Konva from 'konva'; import { Loader } from 'lucide-react'; import { type PDFDocumentProxy } from 'pdfjs-dist'; import { Document as PDFDocument, Page as PDFPage, pdfjs } from 'react-pdf'; import { useCurrentEnvelopeRender } from '@documenso/lib/client-only/providers/envelope-render-provider'; import { cn } from '@documenso/ui/lib/utils'; import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert'; export type LoadedPDFDocument = PDFDocumentProxy; /** * This imports the worker from the `pdfjs-dist` package. */ pdfjs.GlobalWorkerOptions.workerSrc = new URL( 'pdfjs-dist/build/pdf.worker.min.js', import.meta.url, ).toString(); const PDFLoader = () => ( <>

Loading document...

); export type PdfViewerRendererMode = 'editor' | 'preview' | 'signing'; const RendererErrorMessages: Record< PdfViewerRendererMode, { title: MessageDescriptor; description: MessageDescriptor } > = { editor: { title: msg`Configuration Error`, description: msg`There was an issue rendering some fields, please review the fields and try again.`, }, preview: { title: msg`Configuration Error`, description: msg`Something went wrong while rendering the document, some fields may be missing or corrupted.`, }, signing: { title: msg`Configuration Error`, description: msg`Something went wrong while rendering the document, some fields may be missing or corrupted.`, }, }; export type PdfViewerKonvaProps = { className?: string; onDocumentLoad?: () => void; customPageRenderer?: React.FunctionComponent; renderer: PdfViewerRendererMode; [key: string]: unknown; } & Omit, 'onPageClick'>; export const PdfViewerKonva = ({ className, onDocumentLoad, customPageRenderer, renderer, ...props }: PdfViewerKonvaProps) => { const { t } = useLingui(); const $el = useRef(null); const { getPdfBuffer, currentEnvelopeItem, renderError } = useCurrentEnvelopeRender(); const [width, setWidth] = useState(0); const [numPages, setNumPages] = useState(0); const [pdfError, setPdfError] = useState(false); const envelopeItemFile = useMemo(() => { const data = getPdfBuffer(currentEnvelopeItem?.documentDataId || ''); if (!data || data.status !== 'loaded') { return null; } return { data: new Uint8Array(data.file), }; }, [currentEnvelopeItem?.documentDataId, getPdfBuffer]); const onDocumentLoaded = useCallback( (doc: PDFDocumentProxy) => { setNumPages(doc.numPages); }, [onDocumentLoad], ); 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 (
{renderError && ( {t(RendererErrorMessages[renderer].title)} {t(RendererErrorMessages[renderer].description)} )} {envelopeItemFile && Konva ? ( 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.

) : ( )}
} error={

Something went wrong while loading the document.

Please try again or contact our support.

} > {Array(numPages) .fill(null) .map((_, i) => (
''} renderMode={customPageRenderer ? 'custom' : 'canvas'} customRenderer={customPageRenderer} />

Page {i + 1} of {numPages}

))}
) : (
)}
); }; export default PdfViewerKonva;