import * as React from 'react'; import styles from './RequestPortal.module.scss'; import type { IRequestPortalProps } from './IRequestPortalProps'; import { IconSprite } from '../shared/ui/Icon/IconSprite'; import { navigate, useRoute, NavSection } from '../shared/routing'; import { onRequestsChanged, emitRequestsChanged } from '../shared/requestEvents'; import { SideNav } from './SideNav/SideNav'; import { Drawer } from './Drawer/Drawer'; import { CategoryTabs } from './CategoryTabs/CategoryTabs'; import { CATEGORIES, DEFAULT_CATEGORY_ID } from '../data/categories'; import { REQUEST_TYPES } from '../data/requests'; import SubmitFeature from '../features/submit/SubmitFeature'; import ApproveFeature from '../features/approve/ApproveFeature'; import { RequestsTableView } from '../features/myRequests/RequestsTableView'; import { SearchView } from '../features/myRequests/SearchView'; import { getPendingApproval } from '../features/myRequests/myRequests.service'; // Оболочка портала: тёмное боковое меню (разделы) + основная область. // Логики фич тут нет — файл общий, меняется редко. // // Разделы (rpnav): 'new' — подача заявки (вкладки категорий + плитки + форма), // 'approvals'/'own' — таблицы заявок. Клик по строке таблицы открывает заявку // в выезжающей панели ПОВЕРХ раздела (rpmode=approve&rptype=&rpid=), поэтому // раздел под ней сохраняется; та же ссылка приходит из потока Power Automate. const RequestPortal: React.FC = ({ hasTeamsContext, context }) => { const rootClasses = [styles.requestPortal, hasTeamsContext ? styles.teams : ''] .filter(Boolean) .join(' '); const route = useRoute(); const [navCollapsed, setNavCollapsed] = React.useState(false); const [approvalsCount, setApprovalsCount] = React.useState(undefined); const [activeCategoryId, setActiveCategoryId] = React.useState(() => { if (route.mode === 'create' && route.formKey) { const found = REQUEST_TYPES.filter((r) => r.id === route.formKey)[0]; if (found) return found.categoryId; } return DEFAULT_CATEGORY_ID; }); // Счётчик на пункте «На согласовании». Обновляется по тому же событию, что и // сами таблицы (создание заявки, решение согласующего), и на монтировании // (в т.ч. на обновление страницы). Когда сама вкладка «На согласовании» // открыта, RequestsTableView сообщает точное число через onMyTurnCountChange // (ниже) — это перезаписывает значение отсюда, чтобы не было гонки между // двумя независимыми запросами одних и тех же данных. React.useEffect(() => { let cancelled = false; const load = (): void => { getPendingApproval(context) .then((r) => { if (!cancelled) setApprovalsCount(r.totalRows); }) .catch(() => { if (!cancelled) setApprovalsCount(undefined); }); }; load(); const unsubscribe = onRequestsChanged(load); return () => { cancelled = true; unsubscribe(); }; }, [context]); // Переход «создать на основе» (в т.ч. из открытой заявки в панели): переключаем // вкладку категорий на категорию целевой формы, чтобы она совпала с открытой формой. React.useEffect(() => { if (route.mode === 'create' && route.formKey) { const found = REQUEST_TYPES.filter((r) => r.id === route.formKey)[0]; if (found) setActiveCategoryId(found.categoryId); } }, [route.mode, route.formKey]); const goto = (nav: NavSection): void => { // Клик по УЖЕ активному пункту меню не меняет маршрут, значит эффект // загрузки в таблице не перезапустится сам. Шлём событие обновления — // таблица на него подписана и перечитает данные фоном, не убирая с экрана // текущие строки (см. RequestsTableView/SearchView). if (nav === route.nav && route.mode === 'submit') emitRequestsChanged(); navigate({ mode: 'submit', nav }); }; const closeDrawer = (): void => navigate({ mode: 'submit', nav: route.nav }); return (
setNavCollapsed((v) => !v)} />
{route.nav === 'new' ? ( <>
) : route.nav === 'search' ? ( navigate({ mode: 'approve', nav: route.nav, formKey: request.formKey, itemId: request.id, }) } /> ) : ( navigate({ mode: 'approve', nav: route.nav, formKey: request.formKey, itemId: request.id, }) } onMyTurnCountChange={route.nav === 'approvals' ? setApprovalsCount : undefined} /> )}
{route.mode === 'approve' && route.formKey && route.itemId && ( )}
); }; export default RequestPortal;