arm-core/web/src/widgets/FilesDrawer/useLegalEntityFiles.ts
Andrey Epifancev 2ea8a96f26 fix(web): синхронизация встроенного фронта с arm-web — панель файлов в контексте консолидации (#100)
Перенос в arm-core/web правок RSHB/arm-web PR #27 «Панель «Первичные документы»: рабочий стол
консолидации и загрузка в консолидацию» (ветка test, диапазон коммитов fc75edf..100fbfb), только src/:
- services/api/files.ts: filesPath, маршруты /consolidations/{cid}/legal-entities/{le}/files
  вместо ?consolidation_version_id=, которое ядро игнорирует;
- store/slices/consolidations/selectors.ts: текущая консолидация и статус версии (новый файл);
- widgets/FilesDrawer: рабочий стол консолидации, переключатель «Все документы организации»,
  подпись консолидации у файла (consolidationLabel.ts), загрузка только в версии «в работе»;
- widgets/Sidebar: перечитывание списка консолидаций после создания;
- типы api.ts и consolidations.ts, тесты.

Закрывает находку I-1 из #98: загрузка из встроенного фронта снова переводит версию
INITIATED -> DOCUMENTS_PROCESSING. Спеки, CLAUDE.md и scripts из arm-web не переносятся.
После переноса web/src и arm-web@test идентичны (diff -rq пуст).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 10:16:17 +04:00

66 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { message } from 'antd';
import { useCallback, useEffect, useRef, useState } from 'react';
import { ApiError } from '../../api/client';
import { hasPendingFiles, listLegalEntityFiles } from '../../services/api/files';
import type { FileOut } from '../../types/api';
const POLL_MS = 5000;
/**
* Файлы рабочего стола консолидации (`consolidationId`) или все файлы ЮЛ (`null`);
* пока панель открыта и есть UPLOADED/PROCESSING — перечитываем раз в 5 с.
*/
export function useLegalEntityFiles(legalEntityId: string | null, consolidationId: string | null, open: boolean) {
const [files, setFiles] = useState<FileOut[]>([]);
const [loading, setLoading] = useState(false);
const requestRef = useRef(0);
const inFlightRef = useRef(false);
const errorShownRef = useRef(false);
const reload = useCallback(async () => {
if (!legalEntityId) return;
const requestId = ++requestRef.current;
inFlightRef.current = true;
setLoading(true);
try {
const items = await listLegalEntityFiles(legalEntityId, consolidationId);
if (requestId === requestRef.current) {
setFiles(items);
errorShownRef.current = false;
}
} catch (e: unknown) {
// при опросе показываем ошибку один раз на серию; флаг сбрасывается после первого успешного ответа
if (requestId === requestRef.current && !errorShownRef.current) {
errorShownRef.current = true;
message.error(e instanceof ApiError ? e.message : 'Не удалось получить файлы');
}
} finally {
if (requestId === requestRef.current) {
inFlightRef.current = false;
setLoading(false);
}
}
}, [legalEntityId, consolidationId]);
// смена режима (consolidationId) приходит через reload: он пересоздаётся и перезапускает этот эффект
useEffect(() => {
// при смене ЮЛ, режима (консолидация/все) или закрытии панели: старые ответы не применяем, прежние файлы очищаем
requestRef.current++;
inFlightRef.current = false;
errorShownRef.current = false;
setFiles([]);
if (open && legalEntityId) void reload();
}, [open, legalEntityId, reload]);
const pending = hasPendingFiles(files);
useEffect(() => {
if (!open || !pending) return;
const timer = window.setInterval(() => {
if (!inFlightRef.current) void reload(); // не копим параллельные запросы при медленном ответе
}, POLL_MS);
return () => window.clearInterval(timer);
}, [open, pending, reload]);
return { files, loading, reload };
}