Preparation for first deployment-test
This commit is contained in:
3105
dashboard/pnpm-lock.yaml
generated
3105
dashboard/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,56 @@
|
||||
import React from 'react';
|
||||
|
||||
interface CustomMediaInfoPanelProps {
|
||||
mediaId: string;
|
||||
title: string;
|
||||
description: string;
|
||||
eventId?: string;
|
||||
onSave: (data: { title: string; description: string; eventId?: string }) => void;
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
dateModified: number;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
const CustomMediaInfoPanel: React.FC<CustomMediaInfoPanelProps> = ({
|
||||
mediaId,
|
||||
title,
|
||||
name,
|
||||
size,
|
||||
type,
|
||||
dateModified,
|
||||
description,
|
||||
eventId,
|
||||
onSave,
|
||||
}) => {
|
||||
// Hier kannst du Formularfelder und Logik für die Bearbeitung einbauen
|
||||
function formatLocalDate(timestamp: number | undefined | null) {
|
||||
if (!timestamp || isNaN(timestamp)) return '-';
|
||||
const date = new Date(timestamp * 1000);
|
||||
return date.toLocaleString('de-DE');
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h3>Medien-Informationen bearbeiten</h3>
|
||||
{/* Formularfelder für Titel, Beschreibung, Event-Zuordnung */}
|
||||
<div
|
||||
style={{
|
||||
padding: 16,
|
||||
border: '1px solid #eee',
|
||||
borderRadius: 8,
|
||||
background: '#fafafa',
|
||||
maxWidth: 400,
|
||||
}}
|
||||
>
|
||||
<h3 style={{ marginBottom: 12 }}>Datei-Eigenschaften</h3>
|
||||
<div>
|
||||
<b>Name:</b> {name || '-'}
|
||||
</div>
|
||||
<div>
|
||||
<b>Typ:</b> {type || '-'}
|
||||
</div>
|
||||
<div>
|
||||
<b>Größe:</b> {typeof size === 'number' && !isNaN(size) ? size + ' Bytes' : '-'}
|
||||
</div>
|
||||
<div>
|
||||
<b>Geändert:</b> {formatLocalDate(dateModified)}
|
||||
</div>
|
||||
<div>
|
||||
<b>Beschreibung:</b>{' '}
|
||||
{description && description !== 'null' ? (
|
||||
description
|
||||
) : (
|
||||
<span style={{ color: '#888' }}>Keine Beschreibung</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,33 +19,43 @@ interface MediaItem {
|
||||
}
|
||||
|
||||
const Media: React.FC = () => {
|
||||
const [mediaList, setMediaList] = useState<MediaItem[]>([]);
|
||||
const [selectedMedia, setSelectedMedia] = useState<MediaItem | null>(null);
|
||||
// State für die angezeigten Dateidetails
|
||||
const [fileDetails, setFileDetails] = useState<null | {
|
||||
name: string;
|
||||
size: number;
|
||||
type: string;
|
||||
dateModified: number;
|
||||
description?: string | null;
|
||||
}>(null);
|
||||
// Ansicht: 'LargeIcons', 'Details'
|
||||
const [viewMode, setViewMode] = useState<'LargeIcons' | 'Details'>('LargeIcons');
|
||||
|
||||
// Medien vom Server laden
|
||||
useEffect(() => {
|
||||
fetch('/api/eventmedia')
|
||||
.then(res => res.json())
|
||||
.then(setMediaList);
|
||||
}, []);
|
||||
|
||||
|
||||
// Speichern von Metadaten/Event-Zuordnung
|
||||
const handleSave = async (data: { title: string; description: string; eventId?: string }) => {
|
||||
if (!selectedMedia) return;
|
||||
await fetch(`/api/eventmedia/${selectedMedia.id}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
// Nach dem Speichern neu laden
|
||||
const res = await fetch('/api/eventmedia');
|
||||
setMediaList(await res.json());
|
||||
};
|
||||
// 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
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="text-xl font-bold mb-4">Medien</h2>
|
||||
{/* Ansicht-Umschalter */}
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<button
|
||||
className={viewMode === 'LargeIcons' ? 'e-btn e-active' : 'e-btn'}
|
||||
onClick={() => setViewMode('LargeIcons')}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
Icons
|
||||
</button>
|
||||
<button
|
||||
className={viewMode === 'Details' ? 'e-btn e-active' : 'e-btn'}
|
||||
onClick={() => setViewMode('Details')}
|
||||
>
|
||||
Details
|
||||
</button>
|
||||
</div>
|
||||
<FileManagerComponent
|
||||
ajaxSettings={{
|
||||
url: hostUrl + 'operations',
|
||||
@@ -71,18 +81,29 @@ const Media: React.FC = () => {
|
||||
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={(args: any) => {
|
||||
console.log('FileManager popupOpen:', args);
|
||||
}}
|
||||
>
|
||||
<Inject services={[NavigationPane, DetailsView, Toolbar]} />
|
||||
</FileManagerComponent>
|
||||
{selectedMedia && (
|
||||
<CustomMediaInfoPanel
|
||||
mediaId={selectedMedia.id}
|
||||
title={selectedMedia.url}
|
||||
description={selectedMedia.description}
|
||||
eventId={selectedMedia.eventId}
|
||||
onSave={handleSave}
|
||||
/>
|
||||
)}
|
||||
{/* Details-Panel anzeigen, wenn Details verfügbar sind */}
|
||||
{fileDetails && <CustomMediaInfoPanel {...fileDetails} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user