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}`;
+}