diff --git a/webui/src/common/contexts/ToastContext.jsx b/webui/src/common/contexts/ToastContext.jsx new file mode 100644 index 0000000..bb33701 --- /dev/null +++ b/webui/src/common/contexts/ToastContext.jsx @@ -0,0 +1,97 @@ +import React, { createContext, useContext, useState, useCallback } from 'react'; +import Toast from '@/common/components/Toast'; + +const ToastContext = createContext(); + +export const useToast = () => { + const context = useContext(ToastContext); + if (!context) { + throw new Error('useToast must be used within a ToastProvider'); + } + return context; +}; + +export const ToastProvider = ({ children }) => { + const [toasts, setToasts] = useState([]); + + const addToast = useCallback((toast) => { + const id = Date.now() + Math.random(); + const newToast = { + id, + duration: 5000, + ...toast + }; + + setToasts(prev => [...prev, newToast]); + + if (newToast.duration > 0) { + setTimeout(() => { + removeToast(id); + }, newToast.duration); + } + + return id; + }, []); + + const removeToast = useCallback((id) => { + setToasts(prev => prev.filter(toast => toast.id !== id)); + }, []); + + const success = useCallback((message, options = {}) => { + return addToast({ + type: 'success', + message, + ...options + }); + }, [addToast]); + + const error = useCallback((message, options = {}) => { + return addToast({ + type: 'error', + message, + duration: 7000, + ...options + }); + }, [addToast]); + + const warning = useCallback((message, options = {}) => { + return addToast({ + type: 'warning', + message, + ...options + }); + }, [addToast]); + + const info = useCallback((message, options = {}) => { + return addToast({ + type: 'info', + message, + ...options + }); + }, [addToast]); + + const value = { + toasts, + addToast, + removeToast, + success, + error, + warning, + info + }; + + return ( + + {children} +
+ {toasts.map(toast => ( + removeToast(toast.id)} + /> + ))} +
+
+ ); +}; \ No newline at end of file