import { useCallback, useEffect, useRef, useState } from "react"; import { Document, Page } from "react-pdf"; import "react-pdf/dist/esm/Page/AnnotationLayer.css"; import "react-pdf/dist/esm/Page/TextLayer.css"; import ArrowCircleLeftIcon from "@mui/icons-material/ArrowCircleLeft"; import ArrowCircleRightIcon from "@mui/icons-material/ArrowCircleRight"; import { Box, IconButton } from "@mui/material"; import type { CustomTextRenderer, OnGetTextSuccess, } from "node_modules/react-pdf/dist/esm/shared/types"; import { socket } from "../socket"; import { highlightPattern } from "../util/highlighting"; interface PDFViewerProps { pitchBookId: string; currentPage?: number; onPageChange?: (page: number) => void; highlight: { text: string; page: number }[]; focusHighlight: { text: string; page: number }; } export default function PDFViewer({ pitchBookId, currentPage, onPageChange, highlight = [], focusHighlight, }: PDFViewerProps) { const [numPages, setNumPages] = useState(null); const [pageNumber, setPageNumber] = useState(currentPage || 1); const [containerWidth, setContainerWidth] = useState(null); const [pdfKey, setPdfKey] = useState(Date.now()); const containerRef = useRef(null); const [posHighlight, setPosHighlight] = useState([]); const [posHighlightFocus, setPosHighlightFocus] = useState([]); const [textContent, setTextContent] = useState< { posKey: string; text: string; i: number }[] >([]); const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => { setNumPages(numPages); }; useEffect(() => { const updateWidth = () => { if (containerRef.current) { setContainerWidth(containerRef.current.offsetWidth); } }; updateWidth(); window.addEventListener("resize", updateWidth); return () => window.removeEventListener("resize", updateWidth); }, []); useEffect(() => { if (currentPage && currentPage !== pageNumber) { setPageNumber(currentPage); } }, [currentPage, pageNumber]); useEffect(() => { const handleProgress = (data: { id: number; progress: number }) => { if (data.id.toString() === pitchBookId && data.progress === 50) { setPdfKey(Date.now()); } }; socket.on("progress", handleProgress); return () => { socket.off("progress", handleProgress); }; }, [pitchBookId]); const handlePageChange = (newPage: number) => { setPageNumber(newPage); onPageChange?.(newPage); }; const textRenderer: CustomTextRenderer = useCallback( (textItem) => { return highlightPattern( textItem.str, `${textItem.width};${textItem.height};${textItem.transform}`, posHighlight, posHighlightFocus, ); }, [posHighlight, posHighlightFocus], ); useEffect(() => { const tmpPos: string[] = []; const tmpPosHighlight: string[] = []; const textItems = textContent.filter( (e) => e.text !== "" && e.text !== " ", ); textItems.forEach((e, i) => { for (const s of highlight .filter((h) => h.page === pageNumber) .map((h) => h.text)) { if (s.split(" ")[0] === e.text) { if ( s.split(" ").reduce((prev, curr, j) => { return prev && curr === textItems[i + j].text; }, true) ) { for ( let k = textItems[i].i; k < textItems[i + s.split(" ").length].i; k++ ) { tmpPos.push(textContent[k].posKey); } } } } if (focusHighlight?.page === pageNumber) { if (focusHighlight.text.split(" ")[0] === e.text) { if ( focusHighlight.text.split(" ").reduce((prev, curr, j) => { return prev && curr === textItems[i + j].text; }, true) ) { for ( let k = textItems[i].i; k < textItems[i + focusHighlight.text.split(" ").length].i; k++ ) { tmpPosHighlight.push(textContent[k].posKey); } } } } }); setPosHighlight(tmpPos); setPosHighlightFocus(tmpPosHighlight); }, [highlight, focusHighlight, pageNumber, textContent]); const onGetTextSuccess: OnGetTextSuccess = useCallback((fullText) => { setTextContent( fullText.items.map((e, i) => ({ posKey: `${"width" in e ? e.width : 0};${"height" in e ? e.height : 0};${"transform" in e ? e.transform : ""}`, text: "str" in e ? e.str : "", i, })), ); }, []); return ( console.error("Es gab ein Fehler beim Laden des PDFs:", error) } onSourceError={(error) => console.error("Ungültige PDF:", error)} > {containerWidth && ( )} handlePageChange(pageNumber - 1)} > {pageNumber} / {numPages} = (numPages || 1)} onClick={() => handlePageChange(pageNumber + 1)} > ); }