- Added PUT /api/admin/groups/:groupId/reorder endpoint - Implemented handleReorder in ModerationGroupImagesPage - Uses adminRequest API with proper error handling - Same mobile touch support as ManagementPortalPage
158 lines
5.3 KiB
JavaScript
158 lines
5.3 KiB
JavaScript
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { useParams, useNavigate } from 'react-router-dom';
|
|
|
|
// Services
|
|
import { adminGet, adminRequest } from '../../services/adminApi';
|
|
import { handleAdminError } from '../../services/adminErrorHandler';
|
|
import AdminSessionGate from '../AdminAuth/AdminSessionGate.jsx';
|
|
import { useAdminSession } from '../../contexts/AdminSessionContext.jsx';
|
|
|
|
// Components
|
|
import Navbar from '../ComponentUtils/Headers/Navbar';
|
|
import Footer from '../ComponentUtils/Footer';
|
|
import ImageDescriptionManager from '../ComponentUtils/ImageDescriptionManager';
|
|
import GroupMetadataEditor from '../ComponentUtils/GroupMetadataEditor';
|
|
import Loading from '../ComponentUtils/LoadingAnimation/Loading';
|
|
|
|
// UI
|
|
import Swal from 'sweetalert2';
|
|
|
|
/**
|
|
* ModerationGroupImagesPage - Admin page for moderating group images
|
|
*
|
|
* Uses modular components:
|
|
* - ImageDescriptionManager: Edit image descriptions with batch save
|
|
* - GroupMetadataEditor: Edit group metadata with save/discard
|
|
*/
|
|
const ModerationGroupImagesPage = () => {
|
|
const { groupId } = useParams();
|
|
const navigate = useNavigate();
|
|
const [group, setGroup] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
const { isAuthenticated } = useAdminSession();
|
|
|
|
const loadGroup = useCallback(async () => {
|
|
if (!isAuthenticated) {
|
|
return;
|
|
}
|
|
try {
|
|
setLoading(true);
|
|
const data = await adminGet(`/api/admin/groups/${groupId}`);
|
|
|
|
// Transform data similar to ManagementPortalPage
|
|
const transformedData = {
|
|
...data,
|
|
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) {
|
|
await handleAdminError(e, 'Gruppe laden');
|
|
setError('Fehler beim Laden der Gruppe');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [groupId, isAuthenticated]);
|
|
|
|
useEffect(() => {
|
|
if (!isAuthenticated) {
|
|
return;
|
|
}
|
|
loadGroup();
|
|
}, [isAuthenticated, loadGroup]);
|
|
|
|
const handleReorder = async (newOrder) => {
|
|
if (!group || !groupId) {
|
|
console.error('No groupId available for reordering');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const imageIds = newOrder.map(img => img.id);
|
|
|
|
// Use admin API
|
|
await adminRequest(`/api/admin/groups/${groupId}/reorder`, 'PUT', {
|
|
imageIds: imageIds
|
|
});
|
|
|
|
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);
|
|
await handleAdminError(error, 'Reihenfolge speichern');
|
|
}
|
|
};
|
|
|
|
const renderContent = () => {
|
|
if (loading) return <Loading />;
|
|
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 />
|
|
|
|
<div className="container" style={{ minHeight: '80vh', paddingTop: '20px', paddingBottom: '40px' }}>
|
|
{/* Image Descriptions Manager */}
|
|
<ImageDescriptionManager
|
|
images={group.images}
|
|
groupId={groupId}
|
|
onRefresh={loadGroup}
|
|
mode="moderate"
|
|
enableReordering={true}
|
|
onReorder={handleReorder}
|
|
/>
|
|
|
|
{/* Group Metadata Editor */}
|
|
<GroupMetadataEditor
|
|
initialMetadata={group.metadata}
|
|
groupId={groupId}
|
|
onRefresh={loadGroup}
|
|
mode="moderate"
|
|
/>
|
|
|
|
{/* Back Button */}
|
|
<div className="flex-center mt-4">
|
|
<button
|
|
className="btn btn-secondary"
|
|
onClick={() => navigate('/moderation')}
|
|
>
|
|
↩ Zurück zur Übersicht
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="footerContainer"><Footer /></div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<AdminSessionGate>
|
|
{renderContent()}
|
|
</AdminSessionGate>
|
|
);
|
|
};
|
|
|
|
export default ModerationGroupImagesPage;
|