/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useState, useRef, useMemo } from 'react'; import CustomMediaInfoPanel from './components/CustomMediaInfoPanel'; import { FileManagerComponent, Inject, NavigationPane, DetailsView, Toolbar, } from '@syncfusion/ej2-react-filemanager'; import { useAuth } from './useAuth'; const hostUrl = '/api/eventmedia/filemanager/'; // Dein Backend-Endpunkt für FileManager const Media: React.FC = () => { const { user } = useAuth(); const isSuperadmin = useMemo(() => user?.role === 'superadmin', [user]); // State für die angezeigten Dateidetails const [fileDetails] = useState(null); // Ansicht: 'LargeIcons', 'Details' const [viewMode, setViewMode] = useState<'LargeIcons' | 'Details'>('LargeIcons'); const fileManagerRef = useRef(null); // Hilfsfunktion für Datum in Browser-Zeitzone function formatLocalDate(timestamp: number) { if (!timestamp) return ''; const date = new Date(timestamp * 1000); return date.toLocaleString('de-DE'); // Zeigt lokale Zeit des Browsers } // Ansicht umschalten, ohne Remount React.useEffect(() => { if (fileManagerRef.current) { const element = fileManagerRef.current.element as HTMLElement & { ej2_instances?: unknown[] }; if (element && element.ej2_instances && element.ej2_instances[0]) { // Typisiere Instanz als unknown, da kein offizieller Typ vorhanden const instanz = element.ej2_instances[0] as { view: string; dataBind: () => void }; instanz.view = viewMode; instanz.dataBind(); } } }, [viewMode]); type FileItem = { name: string; isFile: boolean }; type ReadSuccessArgs = { action: string; result?: { files?: FileItem[] } }; type FileOpenArgs = { fileDetails?: FileItem; cancel?: boolean }; // Hide "converted" for non-superadmins after data load const handleSuccess = (args: ReadSuccessArgs) => { if (isSuperadmin) return; if (args && args.action === 'read' && args.result && Array.isArray(args.result.files)) { args.result.files = args.result.files.filter((f: FileItem) => !(f.name === 'converted' && !f.isFile)); } }; // Prevent opening the "converted" folder for non-superadmins const handleFileOpen = (args: FileOpenArgs) => { if (!isSuperadmin && args && args.fileDetails && args.fileDetails.name === 'converted' && !args.fileDetails.isFile) { args.cancel = true; } }; return (

Medien

{/* Ansicht-Umschalter */}
{/* Debug-Ausgabe entfernt, da ReactNode erwartet wird */} { try { const el = fileManagerRef.current?.element as any; const inst = el && el.ej2_instances && el.ej2_instances[0]; const maxSeconds = 10 * 60; // 10 minutes if (inst && inst.uploadObj) { // Override the selected handler to validate files before upload const originalSelected = inst.uploadObj.selected; inst.uploadObj.selected = async (args: any) => { const filesData = args && (args.filesData || args.files) ? (args.filesData || args.files) : []; const tooLong: string[] = []; // Helper to get native File object const getRawFile = (fd: any) => fd && (fd.rawFile || fd.file || fd) as File; const checks = Array.from(filesData).map((fd: any) => { const file = getRawFile(fd); if (!file) return Promise.resolve(true); // Only check video MIME types or common extensions if (!file.type.startsWith('video') && !/\.(mp4|webm|ogg|mov|mkv)$/i.test(file.name)) { return Promise.resolve(true); } return new Promise((resolve) => { const url = URL.createObjectURL(file); const video = document.createElement('video'); video.preload = 'metadata'; video.src = url; const clean = () => { try { URL.revokeObjectURL(url); } catch { /* noop */ } }; video.onloadedmetadata = function () { clean(); if (video.duration && video.duration <= maxSeconds) { resolve(true); } else { tooLong.push(`${file.name} (${Math.round(video.duration||0)}s)`); resolve(false); } }; video.onerror = function () { clean(); // If metadata can't be read, allow upload and let server verify resolve(true); }; }); }); const results = await Promise.all(checks); const allOk = results.every(Boolean); if (!allOk) { // Cancel the automatic upload and show error to user args.cancel = true; const msg = `Upload blocked: the following videos exceed ${maxSeconds} seconds:\n` + tooLong.join('\n'); // Use alert for now; replace with project's toast system if available alert(msg); return; } // All files OK — proceed with original selected handler if present, // otherwise start upload programmatically if (typeof originalSelected === 'function') { try { originalSelected.call(inst.uploadObj, args); } catch { /* noop */ } } // If autoUpload is false we need to start upload manually try { inst.uploadObj.upload(args && (args.filesData || args.files)); } catch { /* ignore — uploader may handle starting itself */ } }; } } catch (e) { // Non-fatal: if we can't hook uploader, uploads will behave normally console.error('Could not attach video-duration hook to uploader', e); } }} toolbarSettings={{ items: [ 'NewFolder', 'Upload', 'Download', 'Rename', 'Delete', 'SortBy', 'Refresh', 'Details', ], }} contextMenuSettings={{ file: ['Open', '|', 'Download', '|', 'Rename', 'Delete', '|', 'Details'], folder: ['Open', '|', 'Rename', 'Delete', '|', 'Details'], layout: ['SortBy', 'Refresh', '|', 'View', 'Details'], }} allowMultiSelection={false} view={viewMode} detailsViewSettings={{ columns: [ { field: 'name', headerText: 'Name', minWidth: '120', width: '200' }, { field: 'size', headerText: 'Größe', minWidth: '80', width: '100' }, { field: 'dateModified', headerText: 'Upload-Datum', minWidth: '120', width: '180', template: (data: { dateModified: number }) => formatLocalDate(data.dateModified), }, { field: 'type', headerText: 'Typ', minWidth: '80', width: '100' }, ], }} menuClick={() => {}} > {/* Details-Panel anzeigen, wenn Details verfügbar sind */} {fileDetails && }
); }; export default Media;