import { useEffect, useState } from "react"; import { Check, X, ShieldCheck } from "lucide-react"; import { evidenceUrl, getViolationEvidence } from "../api.js"; import { SensorFusionThumbs, SensorFusionBars } from "./SensorFusion.jsx"; const SEVERITY = { HIGH: { ring: "#fb5e73", chip: "badge danger" }, MEDIUM: { ring: "#fbb540", chip: "badge warning" }, LOW: { ring: "#3b9eff", chip: "badge" }, }; const STATUS_CLASS = { confirmed: "tag ok", dismissed: "tag muted", pending: "tag pending" }; const pretty = (t) => t.replace(/[_-]/g, " ").toLowerCase().replace(/\b\w/g, (c) => c.toUpperCase()); const caseId = (id) => `#NX-${new Date().getFullYear()}-${String(id).padStart(6, "0")}`; // Rich "Violation summary" panel — real detection data in the NETRA layout. export default function ViolationModal({ violation, onClose, onStatus }) { const [meta, setMeta] = useState(null); useEffect(() => { const onKey = (e) => e.key === "Escape" && onClose(); window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [onClose]); useEffect(() => { setMeta(null); if (!violation) return; let alive = true; getViolationEvidence(violation.id) .then((d) => alive && setMeta(d)) .catch(() => {}); return () => { alive = false; }; }, [violation]); if (!violation) return null; const v = violation; const sev = SEVERITY[v.severity] || SEVERITY.LOW; const img = evidenceUrl(v.annotated_image_path); const conf = Math.round(v.confidence * 100); const q = meta?.quality; const condition = meta?.weather_condition; return (
{caseId(v.id)} · auto-detected
Per-frame quality metrics aren’t stored for this record.
)}