import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { Button, Dropdown, Empty, Form, Input, Modal, Popconfirm, Space, Spin, Steps, Tag, Tooltip, Typography, message } from 'antd'; import type { MenuProps } from 'antd'; import { ArrowLeftOutlined, DeleteOutlined, DownOutlined, FolderOpenOutlined, LeftOutlined, LoadingOutlined, MailOutlined, QrcodeOutlined, RedoOutlined, RightOutlined, SaveOutlined, ScissorOutlined, ThunderboltOutlined, UndoOutlined, UserOutlined, ZoomInOutlined, ZoomOutOutlined, } from '@ant-design/icons'; import { useEditor, EditorContent } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import Underline from '@tiptap/extension-underline'; import { inboxApi, type InboxBarcode, type InboxFile, type PostprocessActionResult } from '../api/inbox'; import { paperlessApi } from '../api/paperless'; const ZOOM_MIN = 0.5; const ZOOM_MAX = 3; const ZOOM_STEP = 0.25; const { Title } = Typography; interface DocumentSegment { index: number; pages: number[]; belegname: string | null; } function buildDocuments( pageCount: number, splitPages: number[], deletedPages: number[], manualSplitPages: number[], barcodes: InboxBarcode[], ): DocumentSegment[] { if (pageCount === 0) return []; const deleted = new Set(deletedPages); const splits = new Set([...splitPages, ...manualSplitPages].filter((p) => !deleted.has(p))); const docs: DocumentSegment[] = []; let current: number[] = []; for (let n = 1; n <= pageCount; n++) { if (deleted.has(n)) continue; if (splits.has(n) && current.length > 0) { docs.push({ index: docs.length, pages: current, belegname: null }); current = []; } current.push(n); } if (current.length > 0) { docs.push({ index: docs.length, pages: current, belegname: null }); } // Belegname pro Segment: DateinameTemplate des zugehörigen Barcodes, // Fallback auf templateName falls DateinameTemplate nicht konfiguriert. const sortedBarcodes = [...barcodes].sort((a, b) => a.page - b.page); return docs.map((seg) => { const pageSet = new Set(seg.pages); const barcode = sortedBarcodes.find((b) => pageSet.has(b.page)); const belegname = barcode?.dateinameTemplate || barcode?.templateName || null; return { ...seg, belegname }; }); } function thumbImageStyle(rotation: number, shortSidePx: number): React.CSSProperties { const isQuarter = rotation === 90 || rotation === 270; return { maxWidth: isQuarter ? shortSidePx : '100%', maxHeight: isQuarter ? shortSidePx : '100%', transform: `rotate(${rotation}deg)`, transition: 'transform 0.15s ease-out', }; } function SourceTag({ source }: { source: InboxFile['source'] }) { return source === 'user' ? ( } color="purple"> Persönlich ) : ( } color="blue"> Gemeinsam ); } interface CompareModalProps { open: boolean; paperlessDocumentId: number | null; inboxDocumentId: string; onClose: () => void; onCreateNewVersion: () => void; onSkip: () => void; } function CompareModal({ open, paperlessDocumentId, inboxDocumentId, onClose, onCreateNewVersion, onSkip, }: CompareModalProps) { const [paperlessUrl, setPaperlessUrl] = useState(null); const [inboxUrl, setInboxUrl] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { if (!open || paperlessDocumentId === null) return; let cancelled = false; let papUrl: string | null = null; let inbUrl: string | null = null; setLoading(true); (async () => { try { const [pBlob, iBlob] = await Promise.all([ paperlessApi.getDocumentPdfBlob(paperlessDocumentId), inboxApi.previewBlob(inboxDocumentId), ]); if (cancelled) return; papUrl = URL.createObjectURL(pBlob); inbUrl = URL.createObjectURL(iBlob); setPaperlessUrl(papUrl); setInboxUrl(inbUrl); } catch { if (!cancelled) message.error('Vorschau konnte nicht geladen werden'); } finally { if (!cancelled) setLoading(false); } })(); return () => { cancelled = true; if (papUrl) URL.revokeObjectURL(papUrl); if (inbUrl) URL.revokeObjectURL(inbUrl); setPaperlessUrl(null); setInboxUrl(null); }; }, [open, paperlessDocumentId, inboxDocumentId]); return ( Überspringen , , ]} >
Original (Paperless)
{loading || !paperlessUrl ? (
) : (