132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
import { useEffect, useRef, useState, useCallback } from "react";
|
|
import { Document, Page, pdfjs } 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";
|
|
|
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
|
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
import.meta.url
|
|
).toString();
|
|
|
|
interface PDFViewerProps {
|
|
pitchBookId: string;
|
|
currentPage?: number;
|
|
}
|
|
|
|
export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps) {
|
|
const [numPages, setNumPages] = useState<number | null>(null);
|
|
const [pageNumber, setPageNumber] = useState(currentPage || 1);
|
|
const [containerWidth, setContainerWidth] = useState<number | null>(null);
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
const [highlightLabels, setHighlightLabels] = useState<string[]>([]);
|
|
|
|
const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {
|
|
setNumPages(numPages);
|
|
};
|
|
|
|
// Aktuelle Containergröße berechnen
|
|
useEffect(() => {
|
|
const updateWidth = () => {
|
|
if (containerRef.current) {
|
|
setContainerWidth(containerRef.current.offsetWidth);
|
|
}
|
|
};
|
|
updateWidth();
|
|
window.addEventListener("resize", updateWidth);
|
|
return () => window.removeEventListener("resize", updateWidth);
|
|
}, []);
|
|
|
|
// Seite ändern, wenn prop sich ändert
|
|
useEffect(() => {
|
|
if (currentPage && currentPage !== pageNumber) {
|
|
setPageNumber(currentPage);
|
|
}
|
|
}, [currentPage]);
|
|
|
|
// Highlight-Logik
|
|
useEffect(() => {
|
|
setHighlightLabels(["LTV", "Fondsmanager", "Risikoprofil"]);
|
|
}, []);
|
|
|
|
function highlightPattern(text: string, patterns: string[]) {
|
|
for (const word of patterns) {
|
|
const regex = new RegExp(`(${word})`, "gi");
|
|
text = text.replace(regex, "<mark>$1</mark>");
|
|
}
|
|
return text;
|
|
}
|
|
|
|
const textRenderer = useCallback(
|
|
(textItem: { str: string }) => highlightPattern(textItem.str, highlightLabels),
|
|
[highlightLabels]
|
|
);
|
|
|
|
return (
|
|
<Box
|
|
display="flex"
|
|
flexDirection="column"
|
|
justifyContent="center"
|
|
alignItems="center"
|
|
width="100%"
|
|
height="100%"
|
|
p={2}
|
|
>
|
|
<Box
|
|
ref={containerRef}
|
|
sx={{
|
|
width: "100%",
|
|
maxHeight: "90vh",
|
|
overflow: "auto",
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Document
|
|
file={`http://localhost:5050/api/pitch_book/${pitchBookId}/download`}
|
|
onLoadSuccess={onDocumentLoadSuccess}
|
|
onLoadError={(error) =>
|
|
console.error("Es gab ein Fehler beim Laden des PDFs:", error)
|
|
}
|
|
onSourceError={(error) => console.error("Ungültige PDF:", error)}
|
|
>
|
|
{containerWidth && (
|
|
<Page
|
|
pageNumber={pageNumber}
|
|
width={containerWidth * 0.8}
|
|
customTextRenderer={textRenderer}
|
|
/>
|
|
)}
|
|
</Document>
|
|
</Box>
|
|
<Box
|
|
mt={2}
|
|
display="flex"
|
|
alignItems="center"
|
|
justifyContent="center"
|
|
gap={1}
|
|
>
|
|
<IconButton
|
|
disabled={pageNumber <= 1}
|
|
onClick={() => setPageNumber((p) => p - 1)}
|
|
>
|
|
<ArrowCircleLeftIcon fontSize="large" />
|
|
</IconButton>
|
|
<span>
|
|
{pageNumber} / {numPages}
|
|
</span>
|
|
<IconButton
|
|
disabled={pageNumber >= (numPages || 1)}
|
|
onClick={() => setPageNumber((p) => p + 1)}
|
|
>
|
|
<ArrowCircleRightIcon fontSize="large" />
|
|
</IconButton>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
}
|