diff --git a/frontend/src/components/AppShell.tsx b/frontend/src/components/AppShell.tsx index 1f7bb5d5..e702a5f0 100644 --- a/frontend/src/components/AppShell.tsx +++ b/frontend/src/components/AppShell.tsx @@ -76,6 +76,25 @@ function Header({ onOpenLeftNav, onOpenCalendar }: HeaderProps) { return () => document.removeEventListener("mousedown", handler); }, [userMenuOpen]); + // Закрытие панели уведомлений при клике вне + useEffect(() => { + if (!isNotificationsOpen) return; + const handler = (e: MouseEvent) => { + const target = e.target as Node; + const notificationButton = document.querySelector('[aria-label="Уведомления"]'); + const notificationPanel = document.querySelector('.notification-panel-mobile'); + + const insideButton = notificationButton && notificationButton.contains(target); + const insidePanel = notificationPanel && notificationPanel.contains(target); + + if (!insideButton && !insidePanel) { + setIsNotificationsOpen(false); + } + }; + document.addEventListener("mousedown", handler); + return () => document.removeEventListener("mousedown", handler); + }, [isNotificationsOpen]); + const userInitials = user ? `${user.last_name?.[0] || ''}${user.first_name?.[0] || ''}` : 'Г'; @@ -226,7 +245,7 @@ function Header({ onOpenLeftNav, onOpenCalendar }: HeaderProps) { {/* Мобильная панель уведомлений */}
diff --git a/frontend/src/components/NotificationCenter.tsx b/frontend/src/components/NotificationCenter.tsx index c10e487f..bab4be8b 100644 --- a/frontend/src/components/NotificationCenter.tsx +++ b/frontend/src/components/NotificationCenter.tsx @@ -40,8 +40,12 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen } }; - // Закрытие при клике вне компонента + // Закрытие при клике вне компонента (только для desktop варианта) useEffect(() => { + // Для mobile варианта не используем этот обработчик, + // т.к. панель уведомлений рендерится отдельно в AppShell + if (!isOpen || variant === 'mobile') return; + function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { close(); @@ -50,7 +54,7 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); - }, [isOpen]); + }, [isOpen, variant]); const handleNotificationClick = async (notification: any) => { if (!notification.is_read) { @@ -92,7 +96,10 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen
{unreadCount > 0 && ( )} e.stopPropagation()} className="p-1 hover:bg-slate-100 rounded" aria-label="Настройки" title="Настройки уведомлений" @@ -244,10 +263,10 @@ export function NotificationPanel({ onClose }: { onClose?: () => void }) {
{loading ? ( -
Загрузка...
+
Загрузка...
) : notifications.length === 0 ? ( -
- +
+

Нет уведомлений

) : ( @@ -287,7 +306,13 @@ export function NotificationPanel({ onClose }: { onClose?: () => void }) {
- Показать все + e.stopPropagation()} + className="text-xs text-sky-600 hover:text-sky-700 font-medium" + > + Показать все +
);