pse2_ff/project/frontend/src/components/pdfViewer.tsx

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>
);
}