CognxSafeTrack
feat: backlog P0→P3 — toast system, payments, tenant isolation, feedback handler, i18n parity
6dd9bad | import { useContext } from 'react'; | |
| import { CheckCircle2, XCircle, Info, AlertTriangle, X } from 'lucide-react'; | |
| import { ToastContext, Toast, ToastType } from '@/hooks/useToast'; | |
| const ICONS: Record<ToastType, React.ReactNode> = { | |
| success: <CheckCircle2 className="w-5 h-5 text-emerald-500 flex-shrink-0" />, | |
| error: <XCircle className="w-5 h-5 text-red-500 flex-shrink-0" />, | |
| info: <Info className="w-5 h-5 text-blue-500 flex-shrink-0" />, | |
| warning: <AlertTriangle className="w-5 h-5 text-amber-500 flex-shrink-0" />, | |
| }; | |
| const BG: Record<ToastType, string> = { | |
| success: 'border-emerald-100 bg-white', | |
| error: 'border-red-100 bg-white', | |
| info: 'border-blue-100 bg-white', | |
| warning: 'border-amber-100 bg-white', | |
| }; | |
| function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: () => void }) { | |
| return ( | |
| <div className={`flex items-start gap-3 px-4 py-3 rounded-xl border shadow-lg text-sm font-medium text-slate-800 min-w-[280px] max-w-[400px] animate-[fadeSlideIn_0.2s_ease] ${BG[toast.type]}`}> | |
| {ICONS[toast.type]} | |
| <span className="flex-1 leading-snug">{toast.message}</span> | |
| <button onClick={onRemove} className="text-slate-300 hover:text-slate-500 transition-colors flex-shrink-0 mt-0.5"> | |
| <X className="w-4 h-4" /> | |
| </button> | |
| </div> | |
| ); | |
| } | |
| export function Toaster() { | |
| const { toasts, removeToast } = useContext(ToastContext); | |
| if (toasts.length === 0) return null; | |
| return ( | |
| <div className="fixed top-5 right-5 z-[9999] flex flex-col gap-2 pointer-events-none"> | |
| {toasts.map(t => ( | |
| <div key={t.id} className="pointer-events-auto"> | |
| <ToastItem toast={t} onRemove={() => removeToast(t.id)} /> | |
| </div> | |
| ))} | |
| </div> | |
| ); | |
| } | |