| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- 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) => {
- // Deduplication check
- const isDuplicate = toasts.some(t => t.message === message && t.type === type);
- if (isDuplicate) {
- return;
- }
- const id = Date.now().toString();
- const newToast: ToastItem = { id, type, message, title, duration };
- setToasts(prev => {
- const updated = [...prev, newToast];
- if (updated.length > 5) {
- return updated.slice(updated.length - 5);
- }
- return updated;
- });
- };
- 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-4 right-4 z-[9999] flex flex-col-reverse gap-2 pointer-events-none p-4">
- {toasts.map((toast) => (
- <div
- key={toast.id}
- className="pointer-events-auto transition-all duration-300 ease-in-out"
- >
- <Toast
- type={toast.type}
- title={toast.title}
- message={toast.message}
- duration={toast.duration}
- onClose={() => removeToast(toast.id)}
- />
- </div>
- ))}
- </div>
- </ToastContext.Provider>
- );
- };
|