diff options
Diffstat (limited to 'frontend/src/components/shared/Notification.tsx')
-rw-r--r-- | frontend/src/components/shared/Notification.tsx | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/frontend/src/components/shared/Notification.tsx b/frontend/src/components/shared/Notification.tsx new file mode 100644 index 0000000..bcc11c4 --- /dev/null +++ b/frontend/src/components/shared/Notification.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { CheckCircle, AlertCircle, X } from 'lucide-react'; + +export type NotificationType = 'success' | 'error' | 'info'; + +interface NotificationProps { + type: NotificationType; + message: string; + duration?: number; + onClose?: () => void; +} + +export function Notification({ + type, + message, + duration = 5000, // Default duration of 5 seconds + onClose +}: NotificationProps) { + const [isVisible, setIsVisible] = useState(true); + + useEffect(() => { + if (duration > 0) { + const timer = setTimeout(() => { + setIsVisible(false); + if (onClose) onClose(); + }, duration); + + return () => clearTimeout(timer); + } + }, [duration, onClose]); + + const handleClose = () => { + setIsVisible(false); + if (onClose) onClose(); + }; + + if (!isVisible) return null; + + const getIcon = () => { + switch (type) { + case 'success': + return <CheckCircle className="h-5 w-5 text-green-500" />; + case 'error': + return <AlertCircle className="h-5 w-5 text-red-500" />; + case 'info': + return <AlertCircle className="h-5 w-5 text-blue-500" />; + default: + return null; + } + }; + + const getContainerClasses = () => { + const baseClasses = 'fixed top-4 right-4 z-50 flex items-center gap-3 rounded-lg p-4 shadow-md max-w-sm'; + + switch (type) { + case 'success': + return `${baseClasses} bg-green-50 text-green-800 border border-green-200`; + case 'error': + return `${baseClasses} bg-red-50 text-red-800 border border-red-200`; + case 'info': + return `${baseClasses} bg-blue-50 text-blue-800 border border-blue-200`; + default: + return baseClasses; + } + }; + + return ( + <div className={getContainerClasses()}> + {getIcon()} + <div className="flex-1">{message}</div> + <button + onClick={handleClose} + className="text-gray-500 hover:text-gray-700 focus:outline-none" + aria-label="Close notification" + > + <X className="h-4 w-4" /> + </button> + </div> + ); +}
\ No newline at end of file |