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 (
e.stopPropagation()}>
{img ? Annotated evidence :
}

Violation summary

{caseId(v.id)} · auto-detected

{pretty(v.violation_type)} {v.vehicle_type} {v.license_plate || "—"} {conf}% {v.timestamp ? new Date(v.timestamp).toLocaleString() : "—"} {v.location || "—"} {condition && ( {pretty(condition)} )} {v.status}
Detection & image quality
{q && } {q && } {q && } {!q && (

Per-frame quality metrics aren’t stored for this record.

)}
{q?.corrections?.length > 0 && (
Auto-corrected before detection: {q.corrections.join(" · ")}
)}
On-device signed evidence · tamper-evident chain
sha256: {meta?.evidence_id ? meta.evidence_id.slice(0, 18) : "—"} · signed at edge node {v.location || "H-17"} · raw video never left the pole
); } function Gauge({ value, color }) { const r = 40; const c = 2 * Math.PI * r; const offset = c * (1 - Math.max(0, Math.min(100, value)) / 100); return (
{value} CONF
); } function Fact({ label, tone, mono, children }) { return (
{label} {children}
); } function Bar({ label, value, color, strong }) { const pct = Math.max(0, Math.min(100, value)); return (
{label} {Math.round(value)}
); }