фикс мобильных уведомлений

This commit is contained in:
lizerk 2026-03-11 10:41:41 +03:00
parent b6ad3c3469
commit 9dc0fdb848
2 changed files with 54 additions and 10 deletions

View File

@ -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) {
{/* Мобильная панель уведомлений */}
<div
className={`overflow-hidden transition-all duration-300 lg:hidden ${
className={`notification-panel-mobile overflow-hidden transition-all duration-300 lg:hidden ${
isNotificationsOpen ? "max-h-[70vh] pb-3" : "max-h-0"
}`}
>

View File

@ -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
<div className="flex items-center gap-2">
{unreadCount > 0 && (
<button
onClick={markAllAsRead}
onClick={(e) => {
e.stopPropagation();
markAllAsRead();
}}
className="text-xs text-sky-600 hover:text-sky-700 font-medium"
>
Прочитать все
@ -100,6 +107,7 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen
)}
<Link
href="/notifications/settings"
onClick={(e) => e.stopPropagation()}
className="p-1 hover:bg-slate-100 rounded"
aria-label="Настройки"
title="Настройки уведомлений"
@ -107,7 +115,10 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen
<Settings className="w-4 h-4 text-gray-500" />
</Link>
<button
onClick={() => close()}
onClick={(e) => {
e.stopPropagation();
close();
}}
className="p-1 hover:bg-slate-100 rounded"
aria-label="Закрыть"
>
@ -189,6 +200,7 @@ export function NotificationCenter({ variant = 'default', isOpen: externalIsOpen
<div className="p-3 border-t border-slate-100 bg-slate-50 text-center">
<a
href="/notifications"
onClick={(e) => e.stopPropagation()}
className="text-xs text-sky-600 hover:text-sky-700 font-medium"
>
Показать все уведомления
@ -220,12 +232,19 @@ export function NotificationPanel({ onClose }: { onClose?: () => void }) {
<h3 className="font-semibold text-sm">Уведомления</h3>
<div className="flex items-center gap-2">
{unreadCount > 0 && (
<button onClick={markAllAsRead} className="text-xs text-sky-600 hover:text-sky-700 font-medium">
<button
onClick={(e) => {
e.stopPropagation();
markAllAsRead();
}}
className="text-xs text-sky-600 hover:text-sky-700 font-medium"
>
Прочитать все
</button>
)}
<Link
href="/notifications/settings"
onClick={(e) => e.stopPropagation()}
className="p-1 hover:bg-slate-100 rounded"
aria-label="Настройки"
title="Настройки уведомлений"
@ -244,10 +263,10 @@ export function NotificationPanel({ onClose }: { onClose?: () => void }) {
<div className="overflow-y-auto flex-1">
{loading ? (
<div className="p-6 text-center text-gray-500 text-sm">Загрузка...</div>
<div className="p-8 text-center text-gray-500 text-sm">Загрузка...</div>
) : notifications.length === 0 ? (
<div className="p-6 text-center text-gray-500">
<Bell className="w-10 h-10 mx-auto mb-2 opacity-20 text-gray-400" />
<div className="p-8 text-center text-gray-500">
<Bell className="w-12 h-12 mx-auto mb-2 opacity-20 text-gray-400" />
<p className="text-sm">Нет уведомлений</p>
</div>
) : (
@ -287,7 +306,13 @@ export function NotificationPanel({ onClose }: { onClose?: () => void }) {
</div>
<div className="p-2 border-t border-slate-100 bg-slate-50 text-center">
<a href="/notifications" className="text-xs text-sky-600 hover:text-sky-700 font-medium">Показать все</a>
<a
href="/notifications"
onClick={(e) => e.stopPropagation()}
className="text-xs text-sky-600 hover:text-sky-700 font-medium"
>
Показать все
</a>
</div>
</div>
);