100 lines
2.2 KiB
TypeScript
100 lines
2.2 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect } from 'react'
|
|
|
|
interface ToastProps {
|
|
message: string
|
|
type: 'success' | 'error'
|
|
onClose: () => void
|
|
action?: {
|
|
label: string
|
|
onClick: () => void
|
|
}
|
|
}
|
|
|
|
export default function Toast({ message, type, onClose, action }: ToastProps) {
|
|
useEffect(() => {
|
|
// Don't auto-dismiss if there's an action button
|
|
if (action) return
|
|
|
|
const timer = setTimeout(() => {
|
|
onClose()
|
|
}, 3000)
|
|
|
|
return () => clearTimeout(timer)
|
|
}, [onClose, action])
|
|
|
|
const bgColor =
|
|
type === 'success'
|
|
? 'bg-green-600 dark:bg-green-700'
|
|
: 'bg-red-600 dark:bg-red-700'
|
|
|
|
const icon =
|
|
type === 'success' ? (
|
|
<svg
|
|
className="h-5 w-5"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M5 13l4 4L19 7"
|
|
/>
|
|
</svg>
|
|
) : (
|
|
<svg
|
|
className="h-5 w-5"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
)
|
|
|
|
return (
|
|
<div className="fixed bottom-4 right-4 z-50 animate-in fade-in slide-in-from-bottom-4">
|
|
<div
|
|
className={`flex items-center gap-2 rounded-lg px-4 py-3 text-sm font-medium text-white shadow-lg ${bgColor}`}
|
|
>
|
|
{icon}
|
|
<span>{message}</span>
|
|
{action && (
|
|
<button
|
|
onClick={action.onClick}
|
|
className="ml-2 rounded bg-white/20 px-2 py-0.5 text-xs font-semibold hover:bg-white/30"
|
|
>
|
|
{action.label}
|
|
</button>
|
|
)}
|
|
<button
|
|
onClick={onClose}
|
|
className="ml-2 rounded p-0.5 hover:bg-white/20"
|
|
>
|
|
<svg
|
|
className="h-4 w-4"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|