import * as React from 'react'; import { useState, useEffect, useMemo, useRef } from 'react'; import type { WebPartContext } from '@microsoft/sp-webpart-base'; import styles from './SubmitFeature.module.scss'; import { Icon } from '../../shared/ui/Icon/Icon'; import { RequestGrid } from '../../components/RequestGrid/RequestGrid'; import { getRequestsByCategory, REQUEST_TYPES } from '../../data/requests'; import { getFormComponent } from '../../forms/registry'; import { IRequestType } from '../../models/types'; import { emitRequestsChanged } from '../../shared/requestEvents'; import { confirmDiscardFormChanges, markFormClean } from '../../shared/unsavedChanges'; export interface ISubmitFeatureProps { context: WebPartContext; /** Активная категория. Вкладки теперь рендерятся на уровне портала (RequestPortal), * чтобы оставаться на экране и в режиме согласования — эта фича их только слушает. */ activeCategoryId: string; /** Открыть сразу форму с предзаполнением (производная заявка), минуя плитки. */ initialForm?: { formKey: string; sourceId: number }; /** Открыть сразу форму на РЕДАКТИРОВАНИЕ существующей заявки (черновик/возвращена). */ editForm?: { formKey: string; itemId: number }; } // Фича «Подать заявку»: плитки → беспоук-форма (категории/вкладки — в RequestPortal). // Владелец: автор портала. Живёт целиком в features/submit/**. const SubmitFeature: React.FC = ({ context, activeCategoryId, initialForm, editForm, }) => { // «Создать на основе» и «редактировать» оба сразу открывают нужную форму, минуя плитки. const preOpen = initialForm ?? editForm; const initialSelected = useMemo( () => (preOpen ? REQUEST_TYPES.filter((r) => r.id === preOpen.formKey)[0] ?? null : null), [preOpen] ); const [selectedRequest, setSelectedRequest] = useState(initialSelected); // Смена категории (вкладка сверху) — возвращаемся к списку плиток. // Первый прогон пропускаем: иначе форма, открытая по initialForm «на основе» // (её категория может не совпадать с текущей вкладкой), тут же закроется. const firstCategorySync = useRef(true); useEffect(() => { if (firstCategorySync.current) { firstCategorySync.current = false; return; } setSelectedRequest((prev) => (prev && prev.categoryId !== activeCategoryId ? null : prev)); }, [activeCategoryId]); const requests = getRequestsByCategory(activeCategoryId); // Возврат к плиткам закрывает форму и теряет введённое (раздел остаётся // смонтированным, но состояние формы живёт в самом FormComponent). Спрашиваем, // если правки есть и они не сохранены; после согласия флаг снимаем — терять // уже нечего. const handleBack = (): void => { if (!confirmDiscardFormChanges()) return; markFormClean(); setSelectedRequest(null); }; const renderSelected = (request: IRequestType): React.ReactNode => { const FormComponent = getFormComponent(request.id); // Форма ещё не реализована — показываем заглушку. if (!FormComponent) { return (

Форма «{request.title}» ещё в разработке.

); } // sourceId — «на основе» исходной заявки; editId — правка существующей. const sourceId = initialForm && request.id === initialForm.formKey ? initialForm.sourceId : undefined; const editId = editForm && request.id === editForm.formKey ? editForm.itemId : undefined; // Ленивый рендер формы: её код подтягивается только сейчас, при открытии. return ( Загрузка формы…}> ); }; return (
{selectedRequest ? ( renderSelected(selectedRequest) ) : ( )}
); }; export default SubmitFeature;