diff --git a/src/layouts/AdminLayout.tsx b/src/layouts/AdminLayout.tsx index ab149ea..cc0f69e 100644 --- a/src/layouts/AdminLayout.tsx +++ b/src/layouts/AdminLayout.tsx @@ -24,6 +24,8 @@ import { } from '@ant-design/icons'; import dayjs from 'dayjs'; import { MENU_ITEMS, filterMenuByRole, getMenuSelectedKey, canReceiveWsNotification } from '../config/adminAccess'; +import { getEntityDetailPath } from '../utils/entityRoutes'; +import { useTranslation } from 'react-i18next'; const { Header, Sider, Content } = Layout; const { Text } = Typography; @@ -35,6 +37,7 @@ const AdminLayout: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuthStore(); + const { t } = useTranslation(); const { token: { colorBgContainer } } = theme.useToken(); const [collapsed, setCollapsed] = useState(false); @@ -49,26 +52,21 @@ const AdminLayout: React.FC = () => { return; } const { report_id, target_type, target_id, reason } = msg.data || {}; + const targetPath = target_id ? getEntityDetailPath(target_type, target_id) : undefined; notification.info({ - title: 'Новая жалоба', - description: ( - - Жалоба{' '} - {report_id ? ( - { e.preventDefault(); navigate(`/reports/${report_id}`); }} style={{ fontWeight: 600 }}> - #{report_id} - - ) : ('#?')}{' '} - на {target_type || 'неизвестный тип'}{' '} - {target_id ? ( - { e.preventDefault(); navigate(`/${target_type}s/${target_id}`); }} style={{ fontWeight: 600 }}> - {target_id} - - ) : ('?')}{' '} - {reason ? `(${reason})` : ''} - - ), + key: report_id ? `report-${report_id}` : `report-${Date.now()}`, + message: t('ws.newReport'), + description: [ + report_id ? `Жалоба #${report_id}` : 'Жалоба', + target_type ? `на ${target_type}` : '', + target_id ?? '', + reason ? `(${reason})` : '', + ].filter(Boolean).join(' '), placement: 'topRight', + onClick: () => { + if (report_id) navigate(`/reports/${report_id}`); + else if (targetPath) navigate(targetPath); + }, }); } else if (msg.type === 'ticket_created') { if (!canReceiveWsNotification('ticket_created', user?.role)) { @@ -76,25 +74,19 @@ const AdminLayout: React.FC = () => { } const { ticket_id } = msg.data || {}; notification.info({ - title: 'Новый тикет', - description: ( - - Тикет{' '} - {ticket_id ? ( - { e.preventDefault(); navigate(`/tickets/${ticket_id}`); }} style={{ fontWeight: 600 }}> - #{ticket_id} - - ) : ('без ID')}{' '} - создан - - ), + key: ticket_id ? `ticket-${ticket_id}` : `ticket-${Date.now()}`, + message: t('ws.newTicket'), + description: ticket_id ? `Тикет #${ticket_id} создан` : 'Создан новый тикет', placement: 'topRight', + onClick: () => { + if (ticket_id) navigate(`/tickets/${ticket_id}`); + }, }); } }; window.addEventListener('admin-ws-message', handler as EventListener); return () => window.removeEventListener('admin-ws-message', handler as EventListener); - }, [navigate, user?.role]); + }, [navigate, user?.role, t]); const onlineNodes = React.useMemo(() => { const cutoff = dayjs().subtract(NODE_STATS_THRESHOLD, 'minute'); diff --git a/src/utils/entityRoutes.ts b/src/utils/entityRoutes.ts new file mode 100644 index 0000000..d55916f --- /dev/null +++ b/src/utils/entityRoutes.ts @@ -0,0 +1,14 @@ +/** Маршруты к сущностям по target_type (жалобы, WS-уведомления). */ +const ENTITY_PATH: Record = { + event: 'events', + calendar: 'calendars', + review: 'reviews', + user: 'users', + report: 'reports', + ticket: 'tickets', +}; + +export function getEntityDetailPath(type: string | undefined, id: string): string { + const segment = type ? ENTITY_PATH[type] ?? `${type}s` : 'unknown'; + return `/${segment}/${id}`; +}