diff --git a/src/context/ToastContext.tsx b/src/context/ToastContext.tsx new file mode 100644 index 0000000..c74cf97 --- /dev/null +++ b/src/context/ToastContext.tsx @@ -0,0 +1,48 @@ +import { createContext, useContext, useState, useCallback, type ReactNode } from 'react'; + +export type ToastType = 'success' | 'error' | 'info'; +interface Toast { id: number; message: string; type: ToastType } +interface ToastCtx { show: (message: string, type?: ToastType) => void } + +const ToastContext = createContext({ show: () => {} }); + +export function ToastProvider({ children }: { children: ReactNode }) { + const [toasts, setToasts] = useState([]); + + const show = useCallback((message: string, type: ToastType = 'success') => { + const id = Date.now(); + setToasts(t => [...t, { id, message, type }]); + setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 2800); + }, []); + + const ICONS = { + success: , + error: , + info: <>, + }; + const COLORS = { + success: { bg: 'rgba(34,197,94,0.12)', border: 'rgba(34,197,94,0.3)', icon: '#22c55e' }, + error: { bg: 'rgba(239,68,68,0.12)', border: 'rgba(239,68,68,0.3)', icon: '#ef4444' }, + info: { bg: 'rgba(124,111,224,0.12)',border: 'rgba(124,111,224,0.3)',icon: '#7C6FE0' }, + }; + + return ( + + {children} +
+ {toasts.map(t => { + const c = COLORS[t.type]; + return ( +
+ {ICONS[t.type]} + {t.message} +
+ ); + })} +
+
+ ); +} + +export const useToast = () => useContext(ToastContext);