'use client'; import { useEffect, useState, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Warning as AlertTriangle, Info, WarningCircle as AlertCircle, X, CaretUp as ChevronUp } from '@phosphor-icons/react'; import type { AuditInsight } from '@/types/audit'; const SEVERITY_CONFIG = { info: { border: 'border-accent-cyan/40', bg: 'bg-accent-cyan/5', icon: Info, glow: '0 1px 2px rgba(0,0,0,0.35), 0 10px 24px rgba(74,222,128,0.08)' }, warning: { border: 'border-yellow-500/40', bg: 'bg-yellow-500/5', icon: AlertTriangle, glow: '0 1px 2px rgba(0,0,0,0.35), 0 10px 24px rgba(234,179,8,0.08)' }, critical: { border: 'border-error/40', bg: 'bg-error-dim/5', icon: AlertCircle, glow: '0 1px 2px rgba(0,0,0,0.35), 0 10px 24px rgba(239,68,68,0.08)' }, } as const; export function AuditInsightPanel({ sessionId }: { sessionId: string }) { const [insight, setInsight] = useState(null); const [open, setOpen] = useState(false); const [dismissed, setDismissed] = useState(false); useEffect(() => { if (!sessionId) return; const poll = async () => { try { const r = await fetch(`/api/backend/api/audit/insights?session=${sessionId}`); if (!r.ok) return; const data = await r.json(); if (data.latest) { const newInsight = data.latest as AuditInsight; setInsight((prev) => { if (prev?.id !== newInsight.id) { if (!open) setOpen(true); return newInsight; } return prev; }); } } catch {} }; poll(); const interval = setInterval(poll, 10_000); return () => clearInterval(interval); }, [sessionId, open]); const handleClose = useCallback(() => { setOpen(false); setDismissed(true); }, []); if (dismissed && !open) return null; if (!insight) return null; const cfg = SEVERITY_CONFIG[insight.severity] ?? SEVERITY_CONFIG.info; const Icon = cfg.icon; return ( {open ? (
AI Audit

{insight.insight}

{insight.suggestion && (

→ {insight.suggestion}

)} {insight.affected_steps.length > 0 && (
{insight.affected_steps.map((s) => ( {s} ))}
)}
) : ( { setOpen(true); setDismissed(false); }} className="fixed bottom-6 right-6 z-50 flex items-center gap-2 px-3 py-2 rounded-full" style={{ background: 'var(--glass-panel-bg)', border: '1px solid rgb(var(--glass-border) / var(--glass-border-a))', backdropFilter: 'blur(12px)', boxShadow: cfg.glow, }} > Audit )}
); }