- Add notification service for API calls - Add notification Zustand store with WebSocket integration - Create NotificationBell component with badge - Create NotificationDropdown with recent notifications - Create NotificationItem with icons and actions - Update MainLayout to use NotificationBell Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
/**
|
|
* NotificationBell Component
|
|
* Bell icon with badge showing unread count, opens dropdown on click
|
|
*/
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { Bell } from 'lucide-react';
|
|
import clsx from 'clsx';
|
|
import { useNotificationStore } from '../../../stores/notificationStore';
|
|
import NotificationDropdown from './NotificationDropdown';
|
|
|
|
export default function NotificationBell() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const { unreadCount, fetchUnreadCount, initializeWebSocket } = useNotificationStore();
|
|
|
|
// Fetch unread count on mount and setup WebSocket
|
|
useEffect(() => {
|
|
fetchUnreadCount();
|
|
|
|
// Initialize WebSocket for real-time notifications
|
|
const unsubscribe = initializeWebSocket();
|
|
|
|
// Refresh count periodically
|
|
const interval = setInterval(fetchUnreadCount, 60000);
|
|
|
|
return () => {
|
|
unsubscribe();
|
|
clearInterval(interval);
|
|
};
|
|
}, [fetchUnreadCount, initializeWebSocket]);
|
|
|
|
const toggleDropdown = () => {
|
|
setIsOpen(!isOpen);
|
|
};
|
|
|
|
const closeDropdown = () => {
|
|
setIsOpen(false);
|
|
};
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
onClick={toggleDropdown}
|
|
className={clsx(
|
|
'relative p-2 rounded-lg transition-colors',
|
|
isOpen ? 'bg-gray-700' : 'hover:bg-gray-700'
|
|
)}
|
|
aria-label={`Notificaciones${unreadCount > 0 ? ` (${unreadCount} sin leer)` : ''}`}
|
|
>
|
|
<Bell className="w-5 h-5" />
|
|
|
|
{/* Unread badge */}
|
|
{unreadCount > 0 && (
|
|
<span
|
|
className={clsx(
|
|
'absolute flex items-center justify-center rounded-full bg-red-500 text-white font-medium',
|
|
unreadCount > 9
|
|
? 'top-0 right-0 min-w-[18px] h-[18px] text-[10px] px-1'
|
|
: 'top-1 right-1 w-4 h-4 text-[10px]'
|
|
)}
|
|
>
|
|
{unreadCount > 99 ? '99+' : unreadCount}
|
|
</span>
|
|
)}
|
|
</button>
|
|
|
|
<NotificationDropdown isOpen={isOpen} onClose={closeDropdown} />
|
|
</div>
|
|
);
|
|
}
|