import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import HourglassEmptyIcon from "@mui/icons-material/HourglassEmpty"; import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf"; import { Box, Chip, CircularProgress, LinearProgress, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from "@mui/material"; import { useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { useNavigate } from "@tanstack/react-router"; import { useCallback, useEffect, useState } from "react"; import { socket } from "../socket"; import { fetchPitchBooksById } from "../util/api"; import { pitchBooksQueryOptions } from "../util/query"; import { formatDate } from "../util/date" interface PitchBook { id: number; filename: string; created_at: string; kpi?: | string | { [key: string]: { label: string; entity: string; page: number; status: string; source: string; }[]; }; status?: "processing" | "completed"; } export function PitchBooksTable() { const [loadingPitchBooks, setLoadingPitchBooks] = useState< { id: number; progress: number; filename?: string; created_at?: string; buffer: number; intervalId?: number; }[] >([]); const navigate = useNavigate(); const { data: pitchBooks, isLoading } = useSuspenseQuery( pitchBooksQueryOptions(), ); const handleRowClick = (pitchBookId: number) => { navigate({ to: "/extractedResult/$pitchBook", params: { pitchBook: pitchBookId.toString() }, search: { from: "overview" }, }); }; const onConnection = useCallback(() => { console.log("connected"); }, []); const queryClient = useQueryClient(); const onProgress = useCallback( (progress: { id: number; progress: number }) => { if (progress.progress === 100) { setLoadingPitchBooks((prev) => { const intervalId = prev.find( (item) => item.id === progress.id, )?.intervalId; intervalId && clearInterval(intervalId); return [...prev.filter((item) => item.id !== progress.id)]; }); queryClient.invalidateQueries({ queryKey: pitchBooksQueryOptions().queryKey, }); } else { setLoadingPitchBooks((prev) => { const oldItem = prev.find((item) => item.id === progress.id); let intervalId = oldItem?.intervalId; if (!oldItem) { intervalId = setInterval(() => { setLoadingPitchBooks((prev) => { const oldItem = prev.find((item) => item.id === progress.id); if (!oldItem) return prev; return [ ...prev.filter((e) => e.id !== progress.id), { id: progress.id, progress: oldItem?.progress ?? progress.progress, filename: oldItem?.filename, buffer: oldItem ? oldItem.buffer + 0.5 : 0, intervalId: oldItem.intervalId, created_at: oldItem?.created_at, }, ]; }); }, 400); fetchPitchBooksById(progress.id) .then((res) => { setLoadingPitchBooks((prev) => [ ...prev.filter((item) => item.id !== progress.id), { id: progress.id, progress: progress.progress, filename: res.filename, buffer: 0, intervalId, created_at: res.created_at, }, ]); }) .catch((err) => { console.error(err); }); } return [ ...prev.filter((item) => item.id !== progress.id), { id: progress.id, progress: progress.progress, filename: oldItem?.filename, created_at: oldItem?.created_at, buffer: 0, intervalId, }, ]; }); } }, [queryClient], ); useEffect(() => { socket.on("connect", onConnection); socket.on("progress", onProgress); return () => { socket.off("connect", onConnection); socket.off("progress", onProgress); }; }, [onConnection, onProgress]); const getKPIValue = (pitchBook: PitchBook, fieldName: string): string => { if (!pitchBook.kpi || typeof pitchBook.kpi === "string") { try { const parsedKPI = JSON.parse(pitchBook.kpi as string); // Convert array to object format if needed const kpiObj = Array.isArray(parsedKPI) ? parsedKPI.reduce((acc, item) => { if (!acc[item.label]) acc[item.label] = []; acc[item.label].push(item); return acc; }, {}) : parsedKPI; return kpiObj[fieldName]?.[0]?.entity || "N/A"; } catch { return "N/A"; } } return pitchBook.kpi[fieldName]?.[0]?.entity || "N/A"; }; const getStatus = (pitchBook: PitchBook) => { if ( pitchBook.kpi && ((typeof pitchBook.kpi === "string" && pitchBook.kpi !== "{}") || (typeof pitchBook.kpi === "object" && Object.keys(pitchBook.kpi).length > 0)) ) { return "completed"; } return "processing"; }; if (isLoading) { return ( ); } return ( Fondsname Fondsmanager Hochgeladen am Dateiname Status {loadingPitchBooks .sort((a, b) => a.id - b.id) .map((pitchBook) => ( {pitchBook.created_at && formatDate(pitchBook.created_at)} {pitchBook.filename} } label="In Bearbeitung" size="small" sx={{ backgroundColor: "#fff3e0", color: "#e65100", "& .MuiChip-icon": { color: "#e65100", }, }} /> ))} {pitchBooks .filter( (pitchbook: PitchBook) => !loadingPitchBooks.some((e) => e.id === pitchbook.id), ) .sort( (a: PitchBook, b: PitchBook) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime(), ) .map((pitchBook: PitchBook) => { const status = getStatus(pitchBook); const fundName = getKPIValue(pitchBook, "FONDSNAME") || getKPIValue(pitchBook, "FUND_NAME") || getKPIValue(pitchBook, "NAME"); const manager = getKPIValue(pitchBook, "FONDSMANAGER") || getKPIValue(pitchBook, "MANAGER") || getKPIValue(pitchBook, "PORTFOLIO_MANAGER"); return ( handleRowClick(pitchBook.id)} sx={{ cursor: "pointer", "&:hover": { backgroundColor: "#f9f9f9", }, }} > {fundName} {manager} {formatDate(pitchBook.created_at)} {pitchBook.filename} {status === "completed" ? ( } label="Extraktion Abgeschlossen" size="small" sx={{ backgroundColor: "#e8f5e9", color: "#2e7d32", "& .MuiChip-icon": { color: "#2e7d32", }, }} /> ) : ( } label="In Bearbeitung" size="small" sx={{ backgroundColor: "#fff3e0", color: "#e65100", "& .MuiChip-icon": { color: "#e65100", }, }} /> )} ); })}
{pitchBooks.length === 0 && ( Keine Pitch Books vorhanden )}
); }