Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import { Button, Empty, Spin } from 'antd';
|
||
import { useEffect, useState } from 'react';
|
||
import { ApiError } from '../../api/client';
|
||
import { fetchFileContent } from '../../services/api/files';
|
||
import { saveBlob } from '../../utils/download';
|
||
import PdfPages from './PdfPages';
|
||
|
||
type Loaded = { kind: 'pdf'; data: ArrayBuffer } | { kind: 'image'; url: string } | { kind: 'other'; blob: Blob; filename: string };
|
||
|
||
export function SourcePreview({ fileId }: { fileId: string }) {
|
||
const [loaded, setLoaded] = useState<Loaded | null>(null);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
let cancelled = false;
|
||
let objectUrl: string | null = null;
|
||
setLoaded(null);
|
||
setError(null);
|
||
fetchFileContent(fileId)
|
||
.then(async ({ blob, filename }) => {
|
||
if (cancelled) {
|
||
return;
|
||
}
|
||
if (blob.type === 'application/pdf') {
|
||
const data = await blob.arrayBuffer();
|
||
if (!cancelled) {
|
||
setLoaded({ kind: 'pdf', data });
|
||
}
|
||
} else if (blob.type.startsWith('image/')) {
|
||
objectUrl = URL.createObjectURL(blob);
|
||
setLoaded({ kind: 'image', url: objectUrl });
|
||
} else {
|
||
setLoaded({ kind: 'other', blob, filename: filename ?? 'исходный_файл' });
|
||
}
|
||
})
|
||
.catch((e: unknown) => {
|
||
if (!cancelled) {
|
||
setError(e instanceof ApiError ? e.message : 'Не удалось получить исходный файл');
|
||
}
|
||
});
|
||
return () => {
|
||
cancelled = true;
|
||
if (objectUrl) {
|
||
URL.revokeObjectURL(objectUrl);
|
||
}
|
||
};
|
||
}, [fileId]);
|
||
|
||
if (error) {
|
||
return <Empty description={error} />;
|
||
}
|
||
if (!loaded) {
|
||
return <Spin style={{ margin: 48 }} />;
|
||
}
|
||
if (loaded.kind === 'pdf') {
|
||
return <PdfPages data={loaded.data} />;
|
||
}
|
||
if (loaded.kind === 'image') {
|
||
return <img src={loaded.url} alt='Исходный документ' style={{ width: '100%' }} />;
|
||
}
|
||
return (
|
||
<Empty description='Превью недоступно для этого формата'>
|
||
<Button onClick={() => saveBlob(loaded.blob, loaded.filename)}>Скачать исходник</Button>
|
||
</Empty>
|
||
);
|
||
}
|