94 lines
4.3 KiB
TypeScript
94 lines
4.3 KiB
TypeScript
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';
|
||
|
||
export interface ISubmitFeatureProps {
|
||
context: WebPartContext;
|
||
/** Активная категория. Вкладки теперь рендерятся на уровне портала (RequestPortal),
|
||
* чтобы оставаться на экране и в режиме согласования — эта фича их только слушает. */
|
||
activeCategoryId: string;
|
||
/** Открыть сразу форму с предзаполнением (производная заявка), минуя плитки. */
|
||
initialForm?: { formKey: string; sourceId: number };
|
||
}
|
||
|
||
// Фича «Подать заявку»: плитки → беспоук-форма (категории/вкладки — в RequestPortal).
|
||
// Владелец: автор портала. Живёт целиком в features/submit/**.
|
||
const SubmitFeature: React.FC<ISubmitFeatureProps> = ({ context, activeCategoryId, initialForm }) => {
|
||
// Если пришли по ссылке «создать на основе» — сразу открываем нужную форму.
|
||
const initialSelected = useMemo(
|
||
() => (initialForm ? REQUEST_TYPES.filter((r) => r.id === initialForm.formKey)[0] ?? null : null),
|
||
[initialForm]
|
||
);
|
||
|
||
const [selectedRequest, setSelectedRequest] = useState<IRequestType | null>(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);
|
||
|
||
const handleBack = (): void => setSelectedRequest(null);
|
||
|
||
const renderSelected = (request: IRequestType): React.ReactNode => {
|
||
const FormComponent = getFormComponent(request.id);
|
||
|
||
// Форма ещё не реализована — показываем заглушку.
|
||
if (!FormComponent) {
|
||
return (
|
||
<div className={styles.formPlaceholder}>
|
||
<button type="button" className={styles.backButton} onClick={handleBack}>
|
||
<Icon name="arrow-left" size="sm" />
|
||
<span>К списку заявок</span>
|
||
</button>
|
||
<p className={styles.placeholderText}>Форма «{request.title}» ещё в разработке.</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// sourceId — только для формы, открытой «на основе» исходной заявки.
|
||
const sourceId =
|
||
initialForm && request.id === initialForm.formKey ? initialForm.sourceId : undefined;
|
||
|
||
// Ленивый рендер формы: её код подтягивается только сейчас, при открытии.
|
||
return (
|
||
<React.Suspense fallback={<div className={styles.loading}>Загрузка формы…</div>}>
|
||
<FormComponent
|
||
requestType={request}
|
||
context={context}
|
||
onCancel={handleBack}
|
||
onSaved={emitRequestsChanged}
|
||
sourceId={sourceId}
|
||
/>
|
||
</React.Suspense>
|
||
);
|
||
};
|
||
|
||
return (
|
||
<div className={styles.content}>
|
||
{selectedRequest ? (
|
||
renderSelected(selectedRequest)
|
||
) : (
|
||
<RequestGrid requests={requests} onSelect={setSelectedRequest} />
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default SubmitFeature;
|