import * as React from "react"; import { memo, useContext, useEffect, useState } from "react"; import { inputProps } from "../../interface/inputfieldProps"; import { withJsonFormsControlProps } from "@jsonforms/react"; import { DataContext } from "../../context/Context"; import { Box } from "@mui/system"; import { CircularProgress, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material"; import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos"; import * as pdfjsLib from "pdfjs-dist"; import type { PDFDocumentProxy } from "pdfjs-dist"; import PdfPageRenderer from "./PdfPageRenderer"; import workerSrc from "pdfjs-dist/build/pdf.worker.mjs?url"; pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc; const PdfViewer = memo(function (props: inputProps) { const { uischema, data } = props; const { theme } = useContext(DataContext); const uischemaData = uischema?.config?.main; const styleConfig = uischema?.config?.style; const muiTheme = useTheme(); const isSmallScreen = useMediaQuery(muiTheme.breakpoints.down("sm")); const [pdf, setPdf] = useState(null); const [pdfError, setPdfError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [isLoading, setIsLoading] = useState(false); const pdfRef = React.useRef(null); useEffect(() => { let cancelled = false; let loadingTask: pdfjsLib.PDFDocumentLoadingTask | null = null; const loadPdf = async () => { if (!data) return; setIsLoading(true); setPdfError(null); try { const bytes = Uint8Array.from(window.atob(data), (char) => char.charCodeAt(0)); loadingTask = pdfjsLib.getDocument({ data: bytes }); const pdfDocument = await loadingTask.promise; if (cancelled) { pdfDocument.destroy(); return; } pdfRef.current?.destroy(); pdfRef.current = pdfDocument; setPdf(pdfDocument); setCurrentPage(1); } catch (e: unknown) { if (!cancelled) { setPdfError(e instanceof Error ? e?.message : "Failed to load PDF."); } } finally { if (!cancelled) setIsLoading(false); } }; loadPdf(); return () => { cancelled = true; loadingTask?.destroy(); pdfRef.current?.destroy(); pdfRef.current = null; setPdf(null); }; }, [data]); const totalPages = pdf?.numPages ?? 0; return ( {isLoading ? ( ) : pdf ? ( {totalPages > 1 && ( setCurrentPage((p) => Math.max(1, p - 1))} disabled={currentPage === 1} size="small" aria-label="Previous page" aria-disabled={currentPage === 1} sx={{ color: currentPage === 1 ? "text.disabled" : theme?.myTheme?.palette?.primary?.main, "&:hover": { backgroundColor: `${theme?.myTheme?.palette?.primary?.light}22` }, transition: "color 0.2s", }} > {currentPage} / {totalPages} setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={currentPage === totalPages} size="small" aria-label="Next page" aria-disabled={currentPage === totalPages} sx={{ color: currentPage === totalPages ? "text.disabled" : theme?.myTheme?.palette?.primary?.main, "&:hover": { backgroundColor: `${theme?.myTheme?.palette?.primary?.light}22` }, transition: "color 0.2s", }} > )} ) : pdfError ? ( {pdfError} ) : null} ); }); export default withJsonFormsControlProps(PdfViewer);