import { CloseOutlined, UploadOutlined } from '@ant-design/icons'; import { Button, Drawer, Switch, Tooltip, Typography, message } from 'antd'; import { useEffect, useState } from 'react'; import { ApiError } from '../../api/client'; import { fetchLegalEntity } from '../../services/api/directories/company_groups'; import { postComment } from '../../services/api/documents'; import { summarizeUpload, uploadFiles } from '../../services/api/files'; import { isInWork, useCurrentConsolidation } from '../../store/slices/consolidations/selectors'; import { useAppSelector } from '../../store/store'; import type { FileOut, LegalEntityBrief } from '../../types/api'; import DeleteReasonModal from './DeleteModal'; import { FilesList } from './FilesList'; import ReplaceDocModal from './ReplaceDocModal'; import { UploadDocumentsModal } from './UploadDocumentsModal'; import { consolidationLabel } from './consolidationLabel'; import type { DocumentRow } from './documentRows'; import { useLegalEntityFiles } from './useLegalEntityFiles'; const UPLOAD_DISABLED_HINT = 'Загрузка доступна только в версии в работе'; export function DocumentsDrawer({ open, onClose }: { open: boolean; onClose: () => void }) { const [uploadOpen, setUploadOpen] = useState(false); const [entity, setEntity] = useState(null); const [showAll, setShowAll] = useState(false); const { current_legal_entity_id, consolidations } = useAppSelector((s) => s.consolidations); const current = useCurrentConsolidation(); // консолидация не определена (версии нет в списке ГК) — режим «все» без переключателя (design D-3) const desk = current !== null && !showAll; const consolidationId = desk ? current.consolidation_id : null; const { files, loading, reload } = useLegalEntityFiles(current_legal_entity_id, consolidationId, open); const [targetRow, setTargetRow] = useState(null); const [removalOpen, setRemovalOpen] = useState(false); const canUpload = current !== null && isInWork(current.version_status); const [replaceOpen, setReplaceOpen] = useState(false); const [replacing, setReplacing] = useState(false); const onDelete = () => { void reload(); setRemovalOpen(false); }; const handleReplaceClick = () => { setRemovalOpen(false); setReplaceOpen(true); }; const labelFor = desk ? undefined : (f: FileOut) => consolidationLabel(f.consolidation_id, consolidations, current?.consolidation_id ?? null); useEffect(() => { setShowAll(false); // новая панель открывается столом консоли setEntity(null); if (!open || !current_legal_entity_id) return; let cancelled = false; fetchLegalEntity(current_legal_entity_id) .then((e) => { if (!cancelled) setEntity(e); }) .catch(() => { // без имени: шапка остаётся с подписью, панель не падает }); return () => { cancelled = true; }; }, [open, current_legal_entity_id]); const handleRowDelete = (row: DocumentRow) => { setTargetRow(row); setRemovalOpen(true); }; // Замена = загрузка нового файла в ту же консолидацию: прежний ядро переводит в SUPERSEDED после разбора, // если совпали тип, счёт и период (05-domain-rules §9.5 п. 3). Причина — комментарием к заменяемому документу. const handleReplaceSubmit = async (file: File, reason: string) => { if (!current_legal_entity_id || !targetRow) return; setReplacing(true); try { const result = summarizeUpload(await uploadFiles(current_legal_entity_id, [file], current?.consolidation_id ?? null)); if (result.accepted.length === 0) { message.error(result.rejected[0]?.reason ?? 'Файл не принят'); return; } if (targetRow.documentId) { await postComment(targetRow.documentId, `Замена документа: ${reason}`).catch(() => message.warning('Файл загружен, но причину замены сохранить не удалось'), ); } message.success('Файл загружен: прежний будет заменён после разбора, если совпадут тип, счёт и период'); setReplaceOpen(false); void reload(); } catch (e: unknown) { message.error(e instanceof ApiError ? e.message : 'Не удалось загрузить файл'); } finally { setReplacing(false); } }; const uploadButton = ( ); return ( } aria-label='Закрыть' onClick={onClose} />} title={
Первичные документы {entity && ( <>
{entity.name}
{entity.inn} )}
}>
{canUpload ? ( uploadButton ) : ( {uploadButton} )} {current !== null && ( Все документы организации )}
{current_legal_entity_id && ( setUploadOpen(false)} onUploaded={() => void reload()} /> )} {targetRow && ( <> setRemovalOpen(false)} onDelete={onDelete} onReplace={handleReplaceClick} canReplace={canUpload} /> setReplaceOpen(false)} onSubmit={handleReplaceSubmit} /> )}
); }