From 9dc0fdb8483d5928a50d5fbbeacafbf06a61faa5 Mon Sep 17 00:00:00 2001 From: lizerk Date: Wed, 11 Mar 2026 10:41:41 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BC=D0=BE=D0=B1?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BD=D1=8B=D1=85=20=D1=83=D0=B2=D0=B5=D0=B4?= =?UTF-8?q?=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/AppShell.tsx | 21 ++++++++- .../src/components/NotificationCenter.tsx | 43 +++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) 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" + > + Показать все +
);