/** * ErrorBanner.tsx — Banner dismissible per errori provider * * Legge lastError da providerStore e mostra un banner compatto. * Auto-dismiss dopo 8s. Non blocca la chat. * Nessun prop richiesto — si collega allo store da solo. */ import { memo, useEffect, useRef } from "react"; import { useProviderStore, selectLastError } from "@/store/providerStore"; import { formatErrorBanner } from "@/core/errors"; import { Z_INDEX } from "@/lib/zindex"; const SEVERITY_COLORS = { info: { bg: "rgba(56,189,248,0.08)", border: "rgba(56,189,248,0.22)", text: "#38bdf8" }, warn: { bg: "rgba(251,191,36,0.08)", border: "rgba(251,191,36,0.22)", text: "#fbbf24" }, error: { bg: "rgba(248,113,113,0.08)", border: "rgba(248,113,113,0.22)", text: "#f87171" }, fatal: { bg: "rgba(239,68,68,0.12)", border: "rgba(239,68,68,0.30)", text: "#ef4444" }, } as const; const AUTO_DISMISS_MS = 8_000; const ErrorBanner = memo(function ErrorBanner() { const error = useProviderStore(selectLastError); const clearErr = useProviderStore(s => s.clearError); const timerRef = useRef | null>(null); // Auto-dismiss useEffect(() => { if (!error) return; if (timerRef.current) clearTimeout(timerRef.current); timerRef.current = setTimeout(clearErr, AUTO_DISMISS_MS); return () => { if (timerRef.current) clearTimeout(timerRef.current); }; }, [error, clearErr]); if (!error) return null; const colors = SEVERITY_COLORS[error.severity as keyof typeof SEVERITY_COLORS] ?? SEVERITY_COLORS.warn; const label = formatErrorBanner(error); return (
{/* Severity dot */} {/* Message */} {label} {/* Retry label se applicabile */} {error.retryable && ( ritento… )} {/* Dismiss */}
); } ); export default ErrorBanner;