aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/shared/Notification.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/components/shared/Notification.tsx')
-rw-r--r--frontend/src/components/shared/Notification.tsx82
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