Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 1x 1x 2x 2x 1x 1x 1x 2x 2x 2x 1x 1x 1x 1x 1x | 'use client';
import React, { createContext, useContext, useState, useCallback, useMemo } from 'react';
import { X, CheckCircle, AlertCircle } from 'lucide-react';
type ToastType = 'success' | 'error' | 'info';
interface Toast {
id: string;
message: string;
type: ToastType;
}
interface ToastContextType {
addToast: (message: string, type?: ToastType) => void;
}
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [toasts, setToasts] = useState<Toast[]>([]);
const addToast = useCallback((message: string, type: ToastType = 'success') => {
const id = Math.random().toString(36).substr(2, 9);
setToasts((prev) => [...prev, { id, message, type }]);
// Auto dismiss
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 3000);
}, []);
const removeToast = useCallback((id: string) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, []);
const contextValue = useMemo(() => ({ addToast }), [addToast]);
return (
<ToastContext.Provider value={contextValue}>
{children}
<div className="fixed bottom-6 right-6 z-[100] flex flex-col gap-3 pointer-events-none">
{toasts.map((toast) => (
<div
key={toast.id}
className={`
pointer-events-auto flex items-center gap-3 px-5 py-4 rounded-xl shadow-2xl min-w-[300px] animate-slide-up
${toast.type === 'success' ? 'bg-black text-white' : 'bg-white text-black border border-gray-200'}
`}
>
{toast.type === 'success' ? <CheckCircle size={20} className="text-green-400" /> : <AlertCircle size={20} />}
<p className="text-sm font-bold flex-grow">{toast.message}</p>
<button onClick={() => removeToast(toast.id)} className="opacity-50 hover:opacity-100">
<X size={16} />
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
};
export const useToast = () => {
const context = useContext(ToastContext);
Iif (!context) throw new Error("useToast must be used within ToastProvider");
return context;
}; |