import { Checkbox, Col, Empty, Form, Input, Modal, Row, Select, Spin, message } from 'antd'; import type React from 'react'; import { useEffect, useMemo, useRef, useState } from 'react'; import { ApiError } from '../../api/client'; import { fetchAllLegalEntities, fetchRelatedGroup, fetchRelatedGroups } from '../../services/api/directories/company_groups'; import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks'; import { useAppDispatch, useAppSelector } from '../../store/store'; import type { ConsolidationCreate, LegalEntityBrief, Quarter, RelatedGroupOut } from '../../types/api'; import { preselectMembers } from './preselect'; type Props = { open: boolean; onCancel: () => void; onOk: (values: ConsolidationCreate) => Promise; }; export const NewConsolidationModal: React.FC = ({ open, onCancel, onOk }) => { const [form] = Form.useForm(); const dispatch = useAppDispatch(); const { raw_rows, loading } = useAppSelector((state) => state.company_groups); const [subgroups, setSubgroups] = useState([]); const [loadingSubgroups, setLoadingSubgroups] = useState(false); const subgroupReqRef = useRef(0); const [legEntities, setLegEntities] = useState([]); const [loadingEntities, setLoadingEntities] = useState(false); const legEntReqRef = useRef(0); const relatedReqRef = useRef(0); const [submitting, setSubmitting] = useState(false); const [legEntSearch, setLegEntSearch] = useState(''); const company_group_id = Form.useWatch('company_group_id', form); const related_group_id = Form.useWatch('related_group_id', form); const year = Form.useWatch('year', form); const semester = Form.useWatch('quarter', form); const legEntIds = Form.useWatch('legal_entity_ids', form); const quarterOptions: { value: Quarter; label: string }[] = [ { value: 'Q1', label: '1 квартал' }, { value: 'Q2', label: '2 квартал' }, { value: 'Q3', label: '3 квартал' }, { value: 'Q4', label: '4 квартал' }, ]; useEffect(() => { if (open && raw_rows.length === 0 && !loading) { dispatch(getCompanyGroupsThunk()); } }, [open, raw_rows.length, loading, dispatch]); const isSubmitDisabled = !company_group_id || !related_group_id || !year || !semester || !legEntIds?.length; const yearOptions = useMemo(() => { const y = new Date().getFullYear(); return Array.from({ length: 4 }, (_, i) => ({ value: y - i, label: String(y - i), })); }, []); const clearLegEnts = () => { relatedReqRef.current++; // сменили ГК: ответ по старой ГСК больше не нужен setLegEntities([]); setLoadingEntities(false); setLegEntSearch(''); legEntReqRef.current++; }; const handleGroupChange = async (value?: string) => { form.setFieldsValue({ related_group_id: undefined, legal_entity_ids: [], }); setSubgroups([]); clearLegEnts(); if (!value) return; const reqId = ++subgroupReqRef.current; const leReqId = ++legEntReqRef.current; setLoadingSubgroups(true); setLoadingEntities(true); try { const [dataSubgroups, dataLegEnts] = await Promise.all([fetchRelatedGroups(value), fetchAllLegalEntities(value)]); if (reqId === subgroupReqRef.current) setSubgroups(dataSubgroups.filter((g) => g.kind === 'gsk')); if (leReqId === legEntReqRef.current) setLegEntities(dataLegEnts); } catch (e: unknown) { message.error(e instanceof ApiError ? e.message : 'Не удалось загрузить данные ГК'); } finally { if (reqId === subgroupReqRef.current) setLoadingSubgroups(false); if (leReqId === legEntReqRef.current) setLoadingEntities(false); } }; const handleRelatedGroupChange = async (value?: string) => { form.setFieldsValue({ legal_entity_ids: [] }); if (!value) return; const reqId = ++relatedReqRef.current; try { const detail = await fetchRelatedGroup(value); if (reqId === relatedReqRef.current) { form.setFieldsValue({ legal_entity_ids: preselectMembers( detail.members.map((m) => m.legal_entity_id), legEntities, ), }); } } catch (e: unknown) { message.error(e instanceof ApiError ? e.message : 'Не удалось загрузить состав ГСК'); } }; const resetLocal = () => { relatedReqRef.current++; setSubgroups([]); setLoadingSubgroups(false); subgroupReqRef.current++; clearLegEnts(); setLegEntSearch(''); }; const handleOk = async () => { let values: ConsolidationCreate; try { values = await form.validateFields(); } catch { return; // ошибки полей antd показывает сам } setSubmitting(true); try { await onOk(values); form.resetFields(); resetLocal(); } catch (e: unknown) { message.error(e instanceof ApiError ? e.message : 'Не удалось создать консолидацию'); } finally { setSubmitting(false); } }; const handleCancel = () => { form.resetFields(); resetLocal(); onCancel(); }; const filteredLegEnts = useMemo(() => { if (!legEntSearch) return legEntities; const q = legEntSearch.toLowerCase(); return legEntities.filter((s) => s.name.toLowerCase().includes(q)); }, [legEntities, legEntSearch]); return (
(option?.label as string)?.toLowerCase().includes(input.toLowerCase())} options={subgroups.map((s) => ({ value: s.id, label: s.name }))} onChange={handleRelatedGroupChange} /> {/* ROW 3 - full width block, only after subgroup is selected */} {related_group_id && (
setLegEntSearch(e.target.value)} style={{ marginBottom: 12 }} /> {loadingEntities ? (
) : null} {!loadingEntities && filteredLegEnts.length === 0 && ( )} {!loadingEntities && filteredLegEnts.length > 0 && (
{filteredLegEnts.map((s) => (
{s.name} {s.inn}
))}
)} {!loadingEntities && legEntities.length > 0 && (
Выбрано: {legEntIds?.length ?? 0} / {legEntities.length}
)}
)}
); };