import React from "react"; import { Box, List, ListItem, ListItemIcon, ListItemText, Paper, Typography, } from "@mui/material"; import { CartesianGrid, Cell, ResponsiveContainer, Scatter, ScatterChart, Tooltip as RechartsTooltip, XAxis, YAxis, } from "recharts"; import type { FactAnnotationResponse, TimelineEvent } from "../types"; interface TimelineProps { timeline: TimelineEvent[]; annotations: FactAnnotationResponse[]; } interface PlotPoint { x: number; y: number; year: number; label: string; hasInconsistency: boolean; color: string; } function getEventColor(event: TimelineEvent, ann?: FactAnnotationResponse): string { if (ann) { return ann.status === "consistent" ? "#22c55e" : "#ef4444"; } return event.has_inconsistency ? "#ef4444" : "#94a3b8"; } // Typed loosely so recharts can inject active/payload via cloneElement function ScatterTooltip(props: object): React.ReactElement | null { const { active, payload } = props as { active?: boolean; payload?: Array<{ payload: PlotPoint }>; }; if (!active || !payload?.length) return null; const pt = payload[0].payload; return ( {pt.label} Year: {pt.year} {pt.hasInconsistency && ( Inconsistency detected )} ); } function Timeline({ timeline, annotations }: TimelineProps): React.ReactElement { if (timeline.length === 0) { return ( Temporal Timeline No temporal events to display. ); } const annotationMap = new Map(); annotations.forEach((ann) => { if (!annotationMap.has(ann.sentence_idx)) { annotationMap.set(ann.sentence_idx, ann); } }); const validEvents = timeline.filter((e) => e.year !== null); // Fallback list when not enough parseable years for a chart if (validEvents.length < 2) { return ( Temporal Timeline {timeline.map((event, idx) => { const ann = annotationMap.get(event.sentence_idx); const color = getEventColor(event, ann); return ( {event.label} } secondary={ {event.year !== null ? `Year: ${event.year}` : "Unknown year"} } /> ); })} ); } const plotData: PlotPoint[] = validEvents.map((event, idx) => { const ann = annotationMap.get(event.sentence_idx); return { x: event.year as number, y: idx, year: event.year as number, label: event.label, hasInconsistency: event.has_inconsistency, color: getEventColor(event, ann), }; }); return ( Temporal Timeline String(v)} tick={{ fill: "#94a3b8", fontSize: 12 }} axisLine={{ stroke: "rgba(148,163,184,0.3)" }} tickLine={{ stroke: "rgba(148,163,184,0.3)" }} /> } cursor={false} /> {plotData.map((entry, index) => ( ))} {[ { color: "#22c55e", label: "Consistent" }, { color: "#ef4444", label: "Inconsistent" }, { color: "#94a3b8", label: "Unverified" }, ].map(({ color, label }) => ( {label} ))} ); } export default Timeline;