Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
64 lines
2.9 KiB
TypeScript
64 lines
2.9 KiB
TypeScript
import { Button, Empty, Result, Spin, Tag } from 'antd';
|
||
import { useCallback, useEffect, useState } from 'react';
|
||
import { useNavigate, useParams } from 'react-router-dom';
|
||
import { ApiError } from '../api/client';
|
||
import PageTitle from '../components/PageTitle';
|
||
import { fetchLegalEntity } from '../services/api/directories/company_groups';
|
||
import { getDocument } from '../services/api/documents';
|
||
import type { DocumentOut } from '../types/api';
|
||
import { documentStatusLabel, documentTypeLabel, periodLabel } from '../utils/labels';
|
||
import { OsvDocument } from '../widgets/DocumentReview/OsvDocument';
|
||
import { documentViewKind } from '../widgets/DocumentReview/viewKind';
|
||
|
||
export function DocumentPage() {
|
||
const { document_id } = useParams();
|
||
const navigate = useNavigate();
|
||
const [doc, setDoc] = useState<DocumentOut | null>(null);
|
||
const [entityName, setEntityName] = useState('');
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
const load = useCallback(async () => {
|
||
if (!document_id) return;
|
||
try {
|
||
const d = await getDocument(document_id);
|
||
setDoc(d);
|
||
setError(null);
|
||
fetchLegalEntity(d.legal_entity_id)
|
||
.then((le) => setEntityName(le.name))
|
||
.catch(() => setEntityName(''));
|
||
} catch (e: unknown) {
|
||
setError(e instanceof ApiError ? e.message : 'Не удалось открыть документ');
|
||
}
|
||
}, [document_id]);
|
||
|
||
useEffect(() => {
|
||
void load();
|
||
}, [load]);
|
||
|
||
if (error) {
|
||
return <Result status='warning' title={error} extra={<Button onClick={() => navigate(-1)}>Назад</Button>} />;
|
||
}
|
||
if (!doc) {
|
||
return <Spin style={{ margin: 48 }} />;
|
||
}
|
||
const kind = documentViewKind(doc);
|
||
// Документ в статусе ERROR — данных формы/строк нет: показываем карточку и понятный текст, а не пустой экран.
|
||
const broken = doc.status === 'ERROR' && kind !== 'none';
|
||
return (
|
||
<div style={{ padding: 12, display: 'flex', flexDirection: 'column', height: '100vh', gap: 12 }}>
|
||
<PageTitle
|
||
backable
|
||
location={`Проверка документа${entityName ? ` › ${entityName}` : ''}`}
|
||
header={`${documentTypeLabel(doc.document_type, doc.osv_account_code)} · ${periodLabel(doc.period_year, doc.period_quarter, doc.is_cumulative)}`}
|
||
description={<Tag>{documentStatusLabel(doc.status)}</Tag>}
|
||
/>
|
||
<main style={{ flex: '1 1 auto', minHeight: 0, background: 'white', borderRadius: 12, padding: 12, overflow: 'auto' }}>
|
||
{broken && <Empty description='Документ не удалось распознать — данных для проверки нет' />}
|
||
{!broken && kind === 'osv' && <OsvDocument key={doc.id} document={doc} onChanged={load} />}
|
||
{!broken && kind === 'statement' && <Empty description='Проверка формы — в следующей задаче' />}
|
||
{kind === 'none' && <Empty description='Документ без данных для проверки' />}
|
||
</main>
|
||
</div>
|
||
);
|
||
}
|