Files
2025-12-17 13:56:50 +01:00

75 lines
2.2 KiB
TypeScript

'use client'
import { createContext, useContext, useState, ReactNode } from 'react'
import { X, CheckCircle, AlertCircle, Info } from 'lucide-react'
type ToastType = 'success' | 'error' | 'info'
interface Toast {
id: number
message: string
type: ToastType
}
interface ToastContextType {
showToast: (message: string, type?: ToastType) => void
}
const ToastContext = createContext<ToastContextType | undefined>(undefined)
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([])
const showToast = (message: string, type: ToastType = 'info') => {
const id = Date.now()
setToasts((prev) => [...prev, { id, message, type }])
setTimeout(() => {
setToasts((prev) => prev.filter((toast) => toast.id !== id))
}, 3000)
}
const removeToast = (id: number) => {
setToasts((prev) => prev.filter((toast) => toast.id !== id))
}
return (
<ToastContext.Provider value={{ showToast }}>
{children}
<div className="fixed bottom-24 right-6 z-50 flex flex-col gap-2">
{toasts.map((toast) => (
<div
key={toast.id}
className={`flex items-center gap-3 px-4 py-3 rounded-lg shadow-lg backdrop-blur-sm animate-slide-in-right ${
toast.type === 'success'
? 'bg-green-500/90 text-white'
: toast.type === 'error'
? 'bg-red-500/90 text-white'
: 'bg-blue-500/90 text-white'
}`}
>
{toast.type === 'success' && <CheckCircle size={20} />}
{toast.type === 'error' && <AlertCircle size={20} />}
{toast.type === 'info' && <Info size={20} />}
<p className="flex-1">{toast.message}</p>
<button
onClick={() => removeToast(toast.id)}
className="hover:opacity-70 transition-opacity"
>
<X size={18} />
</button>
</div>
))}
</div>
</ToastContext.Provider>
)
}
export function useToast() {
const context = useContext(ToastContext)
if (!context) {
throw new Error('useToast must be used within ToastProvider')
}
return context
}