Add alerts ssytems to the frontend
This commit is contained in:
@@ -3,11 +3,13 @@ import { clsx } from 'clsx';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthUser, useIsAuthenticated, useAuthActions } from '../../../stores';
|
||||
import { useTheme } from '../../../contexts/ThemeContext';
|
||||
import { useNotifications } from '../../../hooks/useNotifications';
|
||||
import { Button } from '../../ui';
|
||||
import { Avatar } from '../../ui';
|
||||
import { Badge } from '../../ui';
|
||||
import { Modal } from '../../ui';
|
||||
import { TenantSwitcher } from '../../ui/TenantSwitcher';
|
||||
import { NotificationPanel } from '../../ui/NotificationPanel/NotificationPanel';
|
||||
import {
|
||||
Menu,
|
||||
Search,
|
||||
@@ -101,11 +103,21 @@ export const Header = forwardRef<HeaderRef, HeaderProps>(({
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const { logout } = useAuthActions();
|
||||
const { theme, resolvedTheme, setTheme } = useTheme();
|
||||
|
||||
const {
|
||||
notifications,
|
||||
unreadCount,
|
||||
isConnected,
|
||||
markAsRead,
|
||||
markAllAsRead,
|
||||
removeNotification,
|
||||
clearAll
|
||||
} = useNotifications();
|
||||
|
||||
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
|
||||
const [isSearchFocused, setIsSearchFocused] = useState(false);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [isThemeMenuOpen, setIsThemeMenuOpen] = useState(false);
|
||||
const [isNotificationPanelOpen, setIsNotificationPanelOpen] = useState(false);
|
||||
|
||||
const searchInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
@@ -168,6 +180,7 @@ export const Header = forwardRef<HeaderRef, HeaderProps>(({
|
||||
if (e.key === 'Escape') {
|
||||
setIsUserMenuOpen(false);
|
||||
setIsThemeMenuOpen(false);
|
||||
setIsNotificationPanelOpen(false);
|
||||
if (isSearchFocused) {
|
||||
searchInputRef.current?.blur();
|
||||
}
|
||||
@@ -188,6 +201,9 @@ export const Header = forwardRef<HeaderRef, HeaderProps>(({
|
||||
if (!target.closest('[data-theme-menu]')) {
|
||||
setIsThemeMenuOpen(false);
|
||||
}
|
||||
if (!target.closest('[data-notification-panel]')) {
|
||||
setIsNotificationPanelOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', handleClickOutside);
|
||||
@@ -379,25 +395,45 @@ export const Header = forwardRef<HeaderRef, HeaderProps>(({
|
||||
|
||||
{/* Notifications */}
|
||||
{showNotifications && (
|
||||
<div className="relative">
|
||||
<div className="relative" data-notification-panel>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onNotificationClick}
|
||||
className="w-10 h-10 p-0 flex items-center justify-center relative"
|
||||
aria-label={`Notificaciones${notificationCount > 0 ? ` (${notificationCount})` : ''}`}
|
||||
onClick={() => setIsNotificationPanelOpen(!isNotificationPanelOpen)}
|
||||
className={clsx(
|
||||
"w-10 h-10 p-0 flex items-center justify-center relative",
|
||||
!isConnected && "opacity-50",
|
||||
isNotificationPanelOpen && "bg-[var(--bg-secondary)]"
|
||||
)}
|
||||
aria-label={`Notificaciones${unreadCount > 0 ? ` (${unreadCount})` : ''}${!isConnected ? ' - Desconectado' : ''}`}
|
||||
title={!isConnected ? 'Sin conexión en tiempo real' : undefined}
|
||||
aria-expanded={isNotificationPanelOpen}
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<Bell className="h-5 w-5" />
|
||||
{notificationCount > 0 && (
|
||||
<Bell className={clsx(
|
||||
"h-5 w-5 transition-colors",
|
||||
unreadCount > 0 && "text-[var(--color-warning)]"
|
||||
)} />
|
||||
{unreadCount > 0 && (
|
||||
<Badge
|
||||
variant="error"
|
||||
size="sm"
|
||||
className="absolute -top-1 -right-1 min-w-[18px] h-[18px] text-xs flex items-center justify-center"
|
||||
>
|
||||
{notificationCount > 99 ? '99+' : notificationCount}
|
||||
{unreadCount > 99 ? '99+' : unreadCount}
|
||||
</Badge>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<NotificationPanel
|
||||
notifications={notifications}
|
||||
isOpen={isNotificationPanelOpen}
|
||||
onClose={() => setIsNotificationPanelOpen(false)}
|
||||
onMarkAsRead={markAsRead}
|
||||
onMarkAllAsRead={markAllAsRead}
|
||||
onRemoveNotification={removeNotification}
|
||||
onClearAll={clearAll}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user