Compare commits

..

No commits in common. "0eddffcc0bc83091d518264dc5fdba125ed6cee4" and "08eb77d9d7d7d52f37dde8aa3fe20915b3883d96" have entirely different histories.

3 changed files with 163 additions and 135 deletions

View File

@ -1,130 +1,143 @@
import { import {
Table, TableBody, TableCell, TableContainer, Table, TableBody, TableCell, TableContainer,
TableHead, TableRow, Paper, Box, TableHead, TableRow, Paper, Box,
Dialog, DialogActions, DialogContent, DialogTitle, Dialog, DialogActions, DialogContent, DialogTitle,
TextField, Button, Link TextField, Button
} from '@mui/material'; } from '@mui/material';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
import { useState } from 'react'; import { useState } from 'react';
const exampleData = [
{ label: 'Fondsname', value: 'Fund Real Estate Prime Europe', page: 1, status: 'ok' }, // Beispiel-Daten
{ label: 'Fondsmanager', value: '', page: 1, status: 'error' }, const exampleData = [
{ label: 'Risikoprofil', value: 'Core/Core+', page: 10, status: 'warning' }, { label: 'Fondsname', value: 'Fund Real Estate Prime Europe', page: 1, status: 'ok' },
{ label: 'LTV', value: '30-35 %', page: 8, status: 'ok' }, { label: 'Fondsmanager', value: '', page: 1, status: 'error' },
{ label: 'Ausschüttungsrendite', value: '4%', page: 34, status: 'ok' } { label: 'Risikoprofil', value: 'Core/Core+', page: 10, status: 'warning' },
]; { label: 'LTV', value: '30-35 %', page: 8, status: 'ok' }
];
interface KennzahlenTableProps {
onPageClick?: (page: number) => void; // React-Komponente
setSelectedLabel?: (label: string) => void; import { Dispatch, SetStateAction } from 'react';
} type Props = {
setSelectedLabel: Dispatch<SetStateAction<string | null>>;
export default function KennzahlenTable({ onPageClick, setSelectedLabel }: KennzahlenTableProps) {
const [rows, setRows] = useState(exampleData);
const [open, setOpen] = useState(false);
const [currentValue, setCurrentValue] = useState('');
const [currentIndex, setCurrentIndex] = useState<number | null>(null);
const handleEditClick = (value: string, index: number) => {
setCurrentValue(value);
setCurrentIndex(index);
setOpen(true);
}; };
export default function KennzahlenTable({ setSelectedLabel }: Props) {
const handleSave = () => { // Zustand für bearbeitbare Daten
if (currentIndex !== null) { const [rows, setRows] = useState(exampleData);
const updated = [...rows];
updated[currentIndex].value = currentValue; // Zustände für Dialog-Funktion
setRows(updated); const [open, setOpen] = useState(false); // Dialog anzeigen?
} const [currentValue, setCurrentValue] = useState(''); // Eingabewert
setOpen(false); const [currentIndex, setCurrentIndex] = useState<number | null>(null); // Zeilenindex
};
// Beim Klick auf das Stift-Icon: Dialog öffnen
const handleEditClick = (value: string, index: number) => {
setCurrentValue(value);
setCurrentIndex(index);
setOpen(true);
};
// Wert speichern und Dialog schließen
const handleSave = () => {
if (currentIndex !== null) {
const updated = [...rows];
updated[currentIndex].value = currentValue;
setRows(updated);
}
setOpen(false);
};
return (
<>
<TableContainer component={Paper}>
<Table>
{/* Tabellenkopf */}
<TableHead>
<TableRow>
<TableCell><strong>Kennzahl</strong></TableCell>
<TableCell><strong>Wert</strong></TableCell>
<TableCell><strong>Seite</strong></TableCell>
</TableRow>
</TableHead>
{/* Tabelleninhalt */}
<TableBody>
{rows.map((row, index) => {
// Rahmenfarbe anhand Status
let borderColor = 'transparent';
if (row.status === 'error') borderColor = 'red';
else if (row.status === 'warning') borderColor = '#f6ed48';
return (
<TableRow
key={index}
onClick={() => setSelectedLabel(row.label)}
hover
sx={{ cursor: 'pointer' }}
>
return ( {/* Kennzahl */}
<> <TableCell>{row.label}</TableCell>
<TableContainer component={Paper}>
<Table> {/* Wert mit Status-Icons + Stift rechts */}
<TableHead> <TableCell>
<TableRow> <Box
<TableCell><strong>Kennzahl</strong></TableCell> sx={{
<TableCell><strong>Wert</strong></TableCell> border: `2px solid ${borderColor}`,
<TableCell><strong>Seite</strong></TableCell> borderRadius: 1,
</TableRow> padding: '4px 8px',
</TableHead> display: 'flex',
<TableBody> alignItems: 'center',
{rows.map((row, index) => { justifyContent: 'space-between',
let borderColor = 'transparent'; width: '100%',
if (row.status === 'error') borderColor = 'red'; }}
else if (row.status === 'warning') borderColor = '#f6ed48'; >
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
return ( {row.status === 'error' && <ErrorOutlineIcon fontSize="small" color="error" />}
<TableRow {row.status === 'warning' && <SearchIcon fontSize="small" sx={{ color: '#f6ed48' }} />}
key={index} <span>{row.value || '—'}</span>
onClick={() => setSelectedLabel?.(row.label)} </Box>
hover
sx={{ cursor: 'pointer' }} {/* Stift-Icon */}
> <EditIcon
<TableCell>{row.label}</TableCell> fontSize="small"
<TableCell> sx={{ color: '#555', cursor: 'pointer' }}
<Box onClick={() => handleEditClick(row.value, index)}
sx={{ />
border: `2px solid ${borderColor}`,
borderRadius: 1,
padding: '4px 8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
{row.status === 'error' && <ErrorOutlineIcon fontSize="small" color="error" />}
{row.status === 'warning' && <SearchIcon fontSize="small" sx={{ color: '#f6ed48' }} />}
<span>{row.value || '—'}</span>
</Box> </Box>
<EditIcon </TableCell>
fontSize="small"
sx={{ color: '#555', cursor: 'pointer' }} {/* Seitenzahl */}
onClick={() => handleEditClick(row.value, index)} <TableCell>{row.page}</TableCell>
/> </TableRow>
</Box> );
</TableCell> })}
<TableCell> </TableBody>
<Link </Table>
component="button" </TableContainer>
onClick={() => onPageClick?.(row.page)}
sx={{ cursor: 'pointer' }} {/* Dialog zum Bearbeiten */}
> <Dialog open={open} onClose={() => setOpen(false)}>
{row.page} <DialogTitle>Kennzahl bearbeiten</DialogTitle>
</Link> <DialogContent>
</TableCell> <TextField
</TableRow> fullWidth
); value={currentValue}
})} onChange={(e) => setCurrentValue(e.target.value)}
</TableBody> label="Neuer Wert"
</Table> variant="outlined"
</TableContainer> margin="dense"
/>
<Dialog open={open} onClose={() => setOpen(false)}> </DialogContent>
<DialogTitle>Kennzahl bearbeiten</DialogTitle> <DialogActions>
<DialogContent> <Button onClick={() => setOpen(false)}>Abbrechen</Button>
<TextField <Button onClick={handleSave} variant="contained">Speichern</Button>
fullWidth </DialogActions>
value={currentValue} </Dialog>
onChange={(e) => setCurrentValue(e.target.value)} </>
label="Neuer Wert" );
variant="outlined" }
margin="dense"
/>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpen(false)}>Abbrechen</Button>
<Button onClick={handleSave} variant="contained">Speichern</Button>
</DialogActions>
</Dialog>
</>
);
}

View File

@ -28,7 +28,7 @@ export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps)
setNumPages(numPages); setNumPages(numPages);
}; };
// Container-Größe berechnen // Update PDF width on resize
useEffect(() => { useEffect(() => {
const updateWidth = () => { const updateWidth = () => {
if (containerRef.current) { if (containerRef.current) {
@ -41,7 +41,7 @@ export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps)
return () => window.removeEventListener("resize", updateWidth); return () => window.removeEventListener("resize", updateWidth);
}, []); }, []);
// Highlight-Logik // Highlight search logic
useEffect(() => { useEffect(() => {
setHighlightLabels(["LTV", "Fondsmanager", "Risikoprofil"]); setHighlightLabels(["LTV", "Fondsmanager", "Risikoprofil"]);
}, []); }, []);
@ -59,7 +59,7 @@ export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps)
[highlightLabels] [highlightLabels]
); );
// Seite ändern, wenn Prop sich ändert // Update page if prop changes
useEffect(() => { useEffect(() => {
if (currentPage && currentPage !== pageNumber) { if (currentPage && currentPage !== pageNumber) {
setPageNumber(currentPage); setPageNumber(currentPage);
@ -67,7 +67,15 @@ export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps)
}, [currentPage]); }, [currentPage]);
return ( return (
<Box display="flex" flexDirection="column" justifyContent="center" alignItems="center" width="100%" height="100%" p={2}> <Box
display="flex"
flexDirection="column"
justifyContent="center"
alignItems="center"
width="100%"
height="100%"
p={2}
>
<Box <Box
ref={containerRef} ref={containerRef}
sx={{ sx={{
@ -94,14 +102,23 @@ export default function PDFViewer({ pitchBookId, currentPage }: PDFViewerProps)
)} )}
</Document> </Document>
</Box> </Box>
<Box mt={2} display="flex" alignItems="center" justifyContent="center" gap={1}> <Box
mt={2}
display="flex"
alignItems="center"
justifyContent="center"
gap={1}
>
<IconButton disabled={pageNumber <= 1} onClick={() => setPageNumber((p) => p - 1)}> <IconButton disabled={pageNumber <= 1} onClick={() => setPageNumber((p) => p - 1)}>
<ArrowCircleLeftIcon fontSize="large" /> <ArrowCircleLeftIcon fontSize="large" />
</IconButton> </IconButton>
<span> <span>
{pageNumber} / {numPages} {pageNumber} / {numPages}
</span> </span>
<IconButton disabled={pageNumber >= (numPages || 1)} onClick={() => setPageNumber((p) => p + 1)}> <IconButton
disabled={pageNumber >= (numPages || 1)}
onClick={() => setPageNumber((p) => p + 1)}
>
<ArrowCircleRightIcon fontSize="large" /> <ArrowCircleRightIcon fontSize="large" />
</IconButton> </IconButton>
</Box> </Box>

View File

@ -1,7 +1,6 @@
import ContentPasteIcon from "@mui/icons-material/ContentPaste"; import ContentPasteIcon from "@mui/icons-material/ContentPaste";
import { Box, Button, Paper, Typography } from "@mui/material"; import { Box, Button, Paper, Typography } from "@mui/material";
import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useState } from "react";
import KennzahlenTable from "../components/KennzahlenTable"; import KennzahlenTable from "../components/KennzahlenTable";
import PDFViewer from "../components/pdfViewer"; import PDFViewer from "../components/pdfViewer";
@ -13,7 +12,6 @@ function ExtractedResultsPage() {
const { pitchBook } = Route.useParams(); const { pitchBook } = Route.useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const status: "green" | "yellow" | "red" = "red"; const status: "green" | "yellow" | "red" = "red";
const [currentPage, setCurrentPage] = useState(1);
const statusColor = { const statusColor = {
red: "#f43131", red: "#f43131",
@ -60,7 +58,7 @@ function ExtractedResultsPage() {
overflow: "auto", overflow: "auto",
}} }}
> >
<KennzahlenTable onPageClick={setCurrentPage} /> <KennzahlenTable />
</Paper> </Paper>
<Box <Box
display="flex" display="flex"
@ -80,7 +78,7 @@ function ExtractedResultsPage() {
justifyContent: "center", justifyContent: "center",
}} }}
> >
<PDFViewer pitchBookId={pitchBook} currentPage={currentPage} /> <PDFViewer pitchBookId={pitchBook} />
</Paper> </Paper>
<Box mt={2} display="flex" justifyContent="flex-end" gap={2}> <Box mt={2} display="flex" justifyContent="flex-end" gap={2}>
<Button variant="contained" sx={{ backgroundColor: "#383838" }}> <Button variant="contained" sx={{ backgroundColor: "#383838" }}>