feat: Vorschau-Modal für Dokument-Dateien mit Unterstützung für mehrere Formate
- Prop `format` zu DocFullView hinzugefügt, um den Dateityp zu spezifizieren - Dynamische Blob-Generierung mit korrektem MIME-Typ implementiert - Unterstützt Inline-Vorschau für Formate wie PDF, HTML, Bilder, etc. - Fallback zum Download-Link für nicht unterstützte Dateitypen - Ungenutzte Statusfelder wurden entfernt und der modale Inhalt vereinfacht
This commit is contained in:
parent
3e7a22f9e2
commit
1a55bd7748
@ -164,7 +164,7 @@ export function DocItem({
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocFullView data={doc.data} open={openViewDoc} handleClose={() => setOpenViewDoc(false)} />
|
||||
<DocFullView data={doc.data} open={openViewDoc} handleClose={() => setOpenViewDoc(false)} format={doc.extension} />
|
||||
<Card sx={sx} {...other} onClick={() => setOpenViewDoc(true)}>
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
|
||||
@ -1,13 +1,33 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import Box from '@mui/material/Box';
|
||||
import Modal from '@mui/material/Modal';
|
||||
import { TextField } from '@mui/material';
|
||||
|
||||
import { Type } from 'src/api/attribute-service';
|
||||
import { FileFormat } from 'src/api/document-service';
|
||||
|
||||
const getMimeType = (format: FileFormat): string => {
|
||||
switch (format) {
|
||||
case 'pdf': return 'application/pdf';
|
||||
case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
||||
case 'xlsx': return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
case 'csv': return 'text/csv';
|
||||
case 'pptx': return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
||||
case 'txt': return 'text/plain';
|
||||
case 'json': return 'application/json';
|
||||
case 'xml': return 'application/xml';
|
||||
case 'html': return 'text/html';
|
||||
case 'jpg': return 'image/jpeg';
|
||||
case 'png': return 'image/png';
|
||||
case 'svg': return 'image/svg+xml';
|
||||
case 'zip': return 'application/zip';
|
||||
case 'md': return 'text/markdown';
|
||||
default: return 'application/octet-stream';
|
||||
}
|
||||
};
|
||||
|
||||
type DocFullViewProps = {
|
||||
data: Uint8Array;
|
||||
format?: FileFormat;
|
||||
open: boolean;
|
||||
handleClose: () => void;
|
||||
}
|
||||
@ -17,29 +37,70 @@ const style = {
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: 400,
|
||||
bgcolor: 'background.paper',
|
||||
border: '2px solid #000',
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
width: '90%',
|
||||
height: '90%',
|
||||
bgcolor: 'transparent',
|
||||
};
|
||||
|
||||
export default function DocFullView({ data, open, handleClose }: DocFullViewProps) {
|
||||
const [name, setName] = useState<string | undefined>('');
|
||||
const [label, setLabel] = useState<string | undefined>('');
|
||||
const [selectedType, setSelectedType] = useState<Type | null>(null);
|
||||
export default function DocFullView({ data, format, open, handleClose }: DocFullViewProps) {
|
||||
const [objectUrl, setObjectUrl] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !format)
|
||||
return undefined;
|
||||
|
||||
const mimeType = getMimeType(format);
|
||||
const blob = new Blob([data], { type: mimeType });
|
||||
const url = URL.createObjectURL(blob);
|
||||
setObjectUrl(url);
|
||||
|
||||
return () => {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
}, [data, format]);
|
||||
|
||||
const renderContent = () => {
|
||||
if (!objectUrl || !format) return null;
|
||||
|
||||
if (['pdf', 'html', 'txt', 'json', 'xml', 'md'].includes(format)) {
|
||||
return (
|
||||
<iframe
|
||||
src={objectUrl}
|
||||
style={{ width: '100%', height: '100%', border: 'none' }}
|
||||
title={`Viewer for ${format}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (['jpg', 'png', 'svg'].includes(format)) {
|
||||
return (
|
||||
<img
|
||||
src={objectUrl}
|
||||
alt="Document Preview"
|
||||
style={{ maxWidth: '100%', maxHeight: '100%' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Download link for unsupported preview formats
|
||||
return (
|
||||
<Box textAlign="center">
|
||||
<p>This file type cannot be displayed. You can download it below:</p>
|
||||
<a href={objectUrl} download={`document.${format}`}>Download file</a>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
aria-labelledby="modal-modal-title"
|
||||
aria-describedby="modal-modal-description"
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Box sx={style}>
|
||||
<TextField label="Label" variant="filled" value={name} onChange={e => setName(e.target.value)} />
|
||||
<TextField label="Name" variant="filled" value={label} onChange={e => setLabel(e.target.value)} />
|
||||
{renderContent()}
|
||||
</Box>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user