Project-Image-Uploader/frontend/src/Components/Pages/ModerationGroupImagesPage.js
matthias.lotz 5c6f0ce061 feat(frontend): migrate to MUI v5 (phase 4 step 1)
- Replace @material-ui/core -> @mui/material
- Replace @material-ui/icons -> @mui/icons-material
- Switch makeStyles imports to @mui/styles (compat)
- Add @mui/material, @mui/icons-material, @mui/styles, @emotion/react, @emotion/styled to package.json

Notes: Kept makeStyles via @mui/styles for incremental migration; next: replace makeStyles usage with sx/styled where needed.
2025-10-29 20:10:33 +01:00

162 lines
5.8 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Button, Container } from '@mui/material';
import Swal from 'sweetalert2/dist/sweetalert2.js';
import 'sweetalert2/src/sweetalert2.scss';
// Components
import Navbar from '../ComponentUtils/Headers/Navbar';
import Footer from '../ComponentUtils/Footer';
import ImageGallery from '../ComponentUtils/ImageGallery';
import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput';
const ModerationGroupImagesPage = () => {
const { groupId } = useParams();
const navigate = useNavigate();
const [group, setGroup] = useState(null);
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [error, setError] = useState(null);
// selectedImages will hold objects compatible with ImagePreviewGallery
const [selectedImages, setSelectedImages] = useState([]);
const [metadata, setMetadata] = useState({ year: new Date().getFullYear(), title: '', description: '', name: '' });
useEffect(() => {
loadGroup();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [groupId]);
const loadGroup = async () => {
try {
setLoading(true);
const res = await fetch(`/moderation/groups/${groupId}`);
if (!res.ok) throw new Error('Nicht gefunden');
const data = await res.json();
setGroup(data);
// Map group's images to preview-friendly objects
if (data.images && data.images.length > 0) {
const mapped = data.images.map(img => ({
remoteUrl: `/download/${img.fileName}`,
originalName: img.originalName || img.fileName,
id: img.id
}));
setSelectedImages(mapped);
}
// populate metadata from group
setMetadata({
year: data.year || new Date().getFullYear(),
title: data.title || '',
description: data.description || '',
name: data.name || ''
});
} catch (e) {
setError('Fehler beim Laden der Gruppe');
} finally {
setLoading(false);
}
};
const handleSave = async () => {
if (!group) return;
setSaving(true);
try {
// Use metadata state (controlled by DescriptionInput) as source of truth
const payload = {
title: metadata.title,
description: metadata.description,
year: metadata.year,
name: metadata.name
};
const res = await fetch(`/groups/${groupId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new Error(body.message || 'Speichern fehlgeschlagen');
}
Swal.fire({ icon: 'success', title: 'Gruppe erfolgreich aktualisiert', timer: 1500, showConfirmButton: false });
navigate('/moderation');
} catch (e) {
console.error(e);
Swal.fire({ icon: 'error', title: 'Fehler beim Speichern', text: e.message });
} finally {
setSaving(false);
}
};
const handleDeleteImage = async (imageId) => {
if (!window.confirm('Bild wirklich löschen?')) return;
try {
const res = await fetch(`/groups/${groupId}/images/${imageId}`, { method: 'DELETE' });
if (!res.ok) throw new Error('Löschen fehlgeschlagen');
// Aktualisiere lokale Ansicht
const newImages = group.images.filter(img => img.id !== imageId);
setGroup({ ...group, images: newImages, imageCount: (group.imageCount || 0) - 1 });
setSelectedImages(prev => prev.filter(img => img.id !== imageId));
Swal.fire({ icon: 'success', title: 'Bild gelöscht', timer: 1200, showConfirmButton: false });
} catch (e) {
console.error(e);
Swal.fire({ icon: 'error', title: 'Fehler beim Löschen des Bildes' });
}
};
const handleRemoveImage = (indexToRemove) => {
// If it's a remote image mapped with id, call delete
const img = selectedImages[indexToRemove];
if (img && img.id) {
handleDeleteImage(img.id);
return;
}
setSelectedImages(prev => prev.filter((_, index) => index !== indexToRemove));
};
// Note: approve/delete group actions are intentionally removed from this page
if (loading) return <div className="moderation-loading">Lade Gruppe...</div>;
if (error) return <div className="moderation-error">{error}</div>;
if (!group) return <div className="moderation-error">Gruppe nicht gefunden</div>;
return (
<div className="allContainer">
<Navbar />
<Container maxWidth="lg" className="page-container">
<ImageGallery
items={selectedImages}
onDelete={handleRemoveImage}
mode="preview"
showActions={true}
/>
{selectedImages.length > 0 && (
<>
<DescriptionInput metadata={metadata} onMetadataChange={setMetadata} />
<div className="action-buttons">
<Button className="btn btn-secondary" onClick={() => navigate('/moderation')}> Zurück</Button>
<Button className="primary-button" onClick={handleSave} disabled={saving}>{saving ? 'Speichern...' : 'Speichern'}</Button>
</div>
</>
)}
</Container>
<div className="footerContainer"><Footer /></div>
</div>
);
};
export default ModerationGroupImagesPage;