import { useState, useCallback, createContext, useContext, ReactNode, useEffect, useRef } from 'react' import { AlertTriangle, CheckCircle2, CircleAlert, Info, X } from 'lucide-react' import { useLanguage } from '../contexts/LanguageContext' interface DialogState { open: boolean title: string message: string resolve?: (value: boolean) => void } type ToastTone = 'success' | 'error' | 'warning' | 'info' interface ToastState { id: number title: string message: string tone: ToastTone } interface DialogContextType { confirm: (title: string, message: string) => Promise alert: (title: string, message: string) => Promise } const DialogContext = createContext(undefined) const toastStyles = { success: { icon: CheckCircle2, iconClass: 'bg-emerald-50 text-emerald-600 dark:bg-emerald-950 dark:text-emerald-300', borderClass: 'border-emerald-200 dark:border-emerald-800' }, error: { icon: CircleAlert, iconClass: 'bg-red-50 text-red-600 dark:bg-red-950 dark:text-red-300', borderClass: 'border-red-200 dark:border-red-800' }, warning: { icon: AlertTriangle, iconClass: 'bg-amber-50 text-amber-600 dark:bg-amber-950 dark:text-amber-300', borderClass: 'border-amber-200 dark:border-amber-800' }, info: { icon: Info, iconClass: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-300', borderClass: 'border-gray-200 dark:border-gray-700' }, } function toastTone(title: string): ToastTone { if (/失败|错误|异常|不可用|failed|error/i.test(title)) return 'error' if (/提示|警告|未配置|格式|配额|封禁|warning/i.test(title)) return 'warning' if (/完成|成功|已保存|success/i.test(title)) return 'success' return 'info' } export function DialogProvider({ children }: { children: ReactNode }) { const [dialog, setDialog] = useState({ open: false, title: '', message: '' }) const [toasts, setToasts] = useState([]) const toastID = useRef(0) const toastTimers = useRef(new Map()) const { t } = useLanguage() const confirm = useCallback((title: string, message: string) => { return new Promise((resolve) => { setDialog({ open: true, title, message, resolve }) }) }, []) const dismissToast = useCallback((id: number) => { setToasts((current) => current.filter((toast) => toast.id !== id)) const timer = toastTimers.current.get(id) if (timer !== undefined) window.clearTimeout(timer) toastTimers.current.delete(id) }, []) const alert = useCallback((title: string, message: string) => { const id = ++toastID.current setToasts((current) => [...current, { id, title, message, tone: toastTone(title) }].slice(-4)) const timer = window.setTimeout(() => dismissToast(id), 4200) toastTimers.current.set(id, timer) return Promise.resolve() }, [dismissToast]) useEffect(() => () => { toastTimers.current.forEach((timer) => window.clearTimeout(timer)) toastTimers.current.clear() }, []) const close = (result: boolean) => { dialog.resolve?.(result) setDialog({ open: false, title: '', message: '' }) } return ( {children}
{toasts.map((toast) => { const style = toastStyles[toast.tone] const ToastIcon = style.icon return (
{t(toast.title)}
{t(toast.message)}
) })}
{dialog.open && (

{t(dialog.title)}

{t(dialog.message)}

)}
) } export function useDialog() { const ctx = useContext(DialogContext) if (!ctx) throw new Error('useDialog must be used within DialogProvider') return ctx }