| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import React, { createContext, useContext, useState, ReactNode } from 'react';
- import Toast, { ToastType } from '../components/Toast';
- interface ToastItem {
- id: string;
- type: ToastType;
- title?: string;
- message: string;
- duration?: number;
- }
- interface ToastContextType {
- showToast: (type: ToastType, message: string, title?: string, duration?: number) => void;
- showSuccess: (message: string, title?: string) => void;
- showError: (message: string, title?: string) => void;
- showWarning: (message: string, title?: string) => void;
- showInfo: (message: string, title?: string) => void;
- }
- const ToastContext = createContext<ToastContextType | undefined>(undefined);
- export const useToast = () => {
- const context = useContext(ToastContext);
- if (!context) {
- throw new Error('useToast must be used within a ToastProvider');
- }
- return context;
- };
- interface ToastProviderProps {
- children: ReactNode;
- }
- export const ToastProvider: React.FC<ToastProviderProps> = ({ children }) => {
- const [toasts, setToasts] = useState<ToastItem[]>([]);
- const showToast = (type: ToastType, message: string, title?: string, duration?: number) => {
- const id = Date.now().toString();
- const newToast: ToastItem = { id, type, message, title, duration };
- setToasts(prev => {
- // 相同消息去重:如果已存在相同的消息(类型和内容相同),则先移除旧的
- const filtered = prev.filter(t => t.message !== message || t.type !== type);
- return [...filtered, newToast];
- });
- };
- const removeToast = (id: string) => {
- setToasts(prev => prev.filter(toast => toast.id !== id));
- };
- const showSuccess = (message: string, title?: string) => showToast('success', message, title);
- const showError = (message: string, title?: string) => showToast('error', message, title);
- const showWarning = (message: string, title?: string) => showToast('warning', message, title);
- const showInfo = (message: string, title?: string) => showToast('info', message, title);
- return (
- <ToastContext.Provider value={{ showToast, showSuccess, showError, showWarning, showInfo }}>
- {children}
- <div className="fixed bottom-0 right-0 z-[9999] p-4 space-y-3 pointer-events-none w-full max-w-sm flex flex-col items-end">
- {toasts.map((toast) => (
- <div
- key={toast.id}
- className="pointer-events-auto w-full"
- >
- <Toast
- type={toast.type}
- title={toast.title}
- message={toast.message}
- duration={toast.duration}
- onClose={() => removeToast(toast.id)}
- />
- </div>
- ))}
- </div>
- </ToastContext.Provider>
- );
- };
|