315 lines
9.9 KiB
JavaScript
315 lines
9.9 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { useParams, useNavigate } from 'react-router-dom';
|
|
import { Container, Card, CardContent, Typography, Box, Button } from '@mui/material';
|
|
import Swal from 'sweetalert2';
|
|
import NavbarUpload from '../ComponentUtils/Headers/NavbarUpload';
|
|
import Footer from '../ComponentUtils/Footer';
|
|
import Loading from '../ComponentUtils/LoadingAnimation/Loading';
|
|
import ImageGalleryCard from '../ComponentUtils/ImageGalleryCard';
|
|
import ConsentBadges from '../ComponentUtils/ConsentBadges';
|
|
import MultiImageDropzone from '../ComponentUtils/MultiUpload/MultiImageDropzone';
|
|
import ImageDescriptionManager from '../ComponentUtils/ImageDescriptionManager';
|
|
import GroupMetadataEditor from '../ComponentUtils/GroupMetadataEditor';
|
|
import ConsentManager from '../ComponentUtils/ConsentManager';
|
|
import DeleteGroupButton from '../ComponentUtils/DeleteGroupButton';
|
|
|
|
/**
|
|
* ManagementPortalPage - Self-service management for uploaded groups
|
|
*
|
|
* Modulare Struktur mit individuellen Komponenten:
|
|
* - ImageDescriptionManager: Bildbeschreibungen bearbeiten
|
|
* - GroupMetadataEditor: Gruppenmetadaten bearbeiten
|
|
* - ConsentManager: Einwilligungen verwalten
|
|
* - DeleteGroupButton: Gruppe löschen
|
|
*/
|
|
function ManagementPortalPage() {
|
|
const { token } = useParams();
|
|
const navigate = useNavigate();
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
const [group, setGroup] = useState(null);
|
|
|
|
// Load group data
|
|
const loadGroup = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
const res = await fetch(`/api/manage/${token}`);
|
|
|
|
if (res.status === 404) {
|
|
setError('Ungültiger oder abgelaufener Verwaltungslink');
|
|
return;
|
|
}
|
|
|
|
if (res.status === 429) {
|
|
setError('Zu viele Anfragen. Bitte versuchen Sie es später erneut.');
|
|
return;
|
|
}
|
|
|
|
if (!res.ok) {
|
|
throw new Error('Fehler beim Laden der Gruppe');
|
|
}
|
|
|
|
const response = await res.json();
|
|
const data = response.data || response;
|
|
|
|
// Transform data
|
|
const transformedData = {
|
|
...data,
|
|
displayInWorkshop: data.displayInWorkshop || data.display_in_workshop,
|
|
consentTimestamp: data.consentTimestamp || data.consent_timestamp,
|
|
consents: {
|
|
workshopConsent: (data.displayInWorkshop === 1 || data.display_in_workshop === 1),
|
|
socialMediaConsents: (data.socialMediaConsents || [])
|
|
.filter(c => c.consented === 1 && c.revoked === 0)
|
|
.map(c => ({ platformId: c.platform_id, consented: true }))
|
|
},
|
|
metadata: {
|
|
year: data.year || new Date().getFullYear(),
|
|
title: data.title || '',
|
|
description: data.description || '',
|
|
name: data.name || ''
|
|
},
|
|
images: (data.images || []).map(img => ({
|
|
...img,
|
|
remoteUrl: `/download/${img.fileName}`,
|
|
originalName: img.originalName || img.fileName,
|
|
id: img.id,
|
|
imageDescription: img.imageDescription || ''
|
|
}))
|
|
};
|
|
|
|
setGroup(transformedData);
|
|
|
|
} catch (e) {
|
|
console.error('Error loading group:', e);
|
|
setError('Fehler beim Laden der Gruppe');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (token) {
|
|
loadGroup();
|
|
}
|
|
}, [token]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
// Handle adding new images
|
|
const handleImagesSelected = async (newImages) => {
|
|
try {
|
|
const formData = new FormData();
|
|
newImages.forEach(file => {
|
|
formData.append('images', file);
|
|
});
|
|
|
|
const res = await fetch(`/api/manage/${token}/images`, {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => ({}));
|
|
throw new Error(body.error || 'Fehler beim Hochladen');
|
|
}
|
|
|
|
await Swal.fire({
|
|
icon: 'success',
|
|
title: 'Bilder hinzugefügt',
|
|
text: `${newImages.length} Bild(er) wurden erfolgreich hinzugefügt.`,
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
});
|
|
|
|
// Reload group data
|
|
await loadGroup();
|
|
|
|
} catch (error) {
|
|
console.error('Error adding images:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Fehler',
|
|
text: error.message || 'Bilder konnten nicht hinzugefügt werden'
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleReorder = async (newOrder) => {
|
|
if (!group || !group.groupId) {
|
|
console.error('No groupId available for reordering');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const imageIds = newOrder.map(img => img.id);
|
|
|
|
// Use token-based management API
|
|
const response = await fetch(`/api/manage/${token}/reorder`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ imageIds: imageIds })
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Reihenfolge konnte nicht gespeichert werden');
|
|
}
|
|
|
|
await Swal.fire({
|
|
icon: 'success',
|
|
title: 'Gespeichert',
|
|
text: 'Die neue Reihenfolge wurde gespeichert.',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
});
|
|
|
|
await loadGroup();
|
|
} catch (error) {
|
|
console.error('Error reordering images:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Fehler',
|
|
text: error.message || 'Reihenfolge konnte nicht gespeichert werden'
|
|
});
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="allContainer">
|
|
<NavbarUpload />
|
|
<Container maxWidth="lg" sx={{ pt: '20px', pb: '40px', minHeight: '80vh', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
<Loading />
|
|
</Container>
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="allContainer">
|
|
<NavbarUpload />
|
|
<Container maxWidth="lg" sx={{ pt: '20px', pb: '40px', minHeight: '80vh' }}>
|
|
<Card sx={{ borderRadius: '12px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', p: '20px', textAlign: 'center' }}>
|
|
<Typography variant="h5" color="error" gutterBottom>
|
|
{error}
|
|
</Typography>
|
|
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
|
{error}
|
|
</Typography>
|
|
<Button variant="contained" onClick={() => navigate('/')}>
|
|
Zur Startseite
|
|
</Button>
|
|
</Card>
|
|
</Container>
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="allContainer">
|
|
<NavbarUpload />
|
|
|
|
<Container maxWidth="lg" sx={{ pt: '20px', pb: '40px', minHeight: '80vh' }}>
|
|
<Card sx={{ borderRadius: '12px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', p: '20px', mb: '20px' }}>
|
|
<CardContent>
|
|
<Typography sx={{ fontFamily: 'roboto', fontWeight: 400, fontSize: '28px', textAlign: 'center', mb: '10px', color: '#333333' }}>
|
|
Mein Upload verwalten
|
|
</Typography>
|
|
<Typography sx={{ fontFamily: 'roboto', fontWeight: 300, fontSize: '16px', color: '#666666', textAlign: 'center', mb: '30px' }}>
|
|
Hier können Sie Ihre hochgeladenen Bilder verwalten, Metadaten bearbeiten und Einwilligungen ändern.
|
|
</Typography>
|
|
|
|
{/* Group Overview */}
|
|
{group && (
|
|
<Box sx={{ mb: 3 }}>
|
|
<ImageGalleryCard
|
|
item={group}
|
|
showActions={false}
|
|
isPending={!group.approved}
|
|
mode="group"
|
|
hidePreview={true}
|
|
/>
|
|
|
|
<Box sx={{ mt: 2 }}>
|
|
<Typography variant="subtitle2" gutterBottom sx={{ fontWeight: 600 }}>
|
|
Erteilte Einwilligungen:
|
|
</Typography>
|
|
<ConsentBadges group={group} />
|
|
</Box>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Add Images Dropzone */}
|
|
<Box sx={{ mb: 3 }}>
|
|
<Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
|
|
Weitere Bilder hinzufügen
|
|
</Typography>
|
|
<MultiImageDropzone
|
|
onImagesSelected={handleImagesSelected}
|
|
selectedImages={[]}
|
|
/>
|
|
</Box>
|
|
|
|
{/* Image Descriptions Manager */}
|
|
{group && group.images && group.images.length > 0 && (
|
|
<Box sx={{ mb: 3 }}>
|
|
<ImageDescriptionManager
|
|
images={group.images}
|
|
token={token}
|
|
enableReordering={true}
|
|
onReorder={handleReorder}
|
|
onRefresh={loadGroup}
|
|
/>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Group Metadata Editor */}
|
|
{group && (
|
|
<Box sx={{ mb: 3 }}>
|
|
<GroupMetadataEditor
|
|
initialMetadata={group.metadata}
|
|
token={token}
|
|
onRefresh={loadGroup}
|
|
/>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Consent Manager */}
|
|
{group && (
|
|
<Box sx={{ mb: 3 }}>
|
|
<ConsentManager
|
|
initialConsents={group.consents}
|
|
token={token}
|
|
groupId={group.groupId}
|
|
onRefresh={loadGroup}
|
|
/>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Delete Group Button */}
|
|
{group && (
|
|
<Box sx={{ mt: 4, display: 'flex', justifyContent: 'center' }}>
|
|
<DeleteGroupButton
|
|
token={token}
|
|
groupName={group.title || group.name || 'diese Gruppe'}
|
|
/>
|
|
</Box>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</Container>
|
|
|
|
<div className="footerContainer">
|
|
<Footer />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default ManagementPortalPage;
|
|
|