diff --git a/frontend/src/Components/Pages/ModerationGroupImagesPage.js b/frontend/src/Components/Pages/ModerationGroupImagesPage.js index 23aecc5..cd27420 100644 --- a/frontend/src/Components/Pages/ModerationGroupImagesPage.js +++ b/frontend/src/Components/Pages/ModerationGroupImagesPage.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Button, Container } from '@mui/material'; import Swal from 'sweetalert2/dist/sweetalert2.js'; @@ -10,6 +10,9 @@ import Footer from '../ComponentUtils/Footer'; import ImageGallery from '../ComponentUtils/ImageGallery'; import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput'; +// Services +import { updateImageOrder } from '../../services/reorderService'; + @@ -24,6 +27,7 @@ const ModerationGroupImagesPage = () => { // selectedImages will hold objects compatible with ImagePreviewGallery const [selectedImages, setSelectedImages] = useState([]); const [metadata, setMetadata] = useState({ year: new Date().getFullYear(), title: '', description: '', name: '' }); + const [isReordering, setIsReordering] = useState(false); useEffect(() => { loadGroup(); @@ -122,6 +126,53 @@ const ModerationGroupImagesPage = () => { setSelectedImages(prev => prev.filter((_, index) => index !== indexToRemove)); }; + // Handle drag-and-drop reordering + const handleReorder = useCallback(async (reorderedItems) => { + if (isReordering) return; // Prevent concurrent reordering + + try { + setIsReordering(true); + console.log('🔄 Reordering images:', reorderedItems.map(img => ({ id: img.id, fileName: img.fileName }))); + + // Update local state immediately (optimistic update) + setSelectedImages(reorderedItems); + + // Also update group state to keep consistency + if (group) { + setGroup({ ...group, images: reorderedItems }); + } + + // Send API request + await updateImageOrder(groupId, reorderedItems.map(img => img.id)); + + // Show success feedback + Swal.fire({ + icon: 'success', + title: 'Reihenfolge gespeichert', + timer: 1500, + showConfirmButton: false, + toast: true, + position: 'top-end' + }); + + } catch (error) { + console.error('❌ Fehler beim Neuordnen:', error); + + // Rollback on error - reload original order + await loadGroup(); + + Swal.fire({ + icon: 'error', + title: 'Fehler beim Speichern', + text: 'Reihenfolge konnte nicht gespeichert werden', + timer: 3000, + showConfirmButton: false + }); + } finally { + setIsReordering(false); + } + }, [groupId, group, isReordering, loadGroup]); + // Note: approve/delete group actions are intentionally removed from this page if (loading) return
Lade Gruppe...
; @@ -136,6 +187,9 @@ const ModerationGroupImagesPage = () => { diff --git a/frontend/src/Components/Pages/PublicGroupImagesPage.js b/frontend/src/Components/Pages/PublicGroupImagesPage.js index 411900b..a427620 100644 --- a/frontend/src/Components/Pages/PublicGroupImagesPage.js +++ b/frontend/src/Components/Pages/PublicGroupImagesPage.js @@ -58,6 +58,7 @@ const PublicGroupImagesPage = () => { id: img.id })) : []} showActions={false} + enableReordering={false} mode="single-image" emptyMessage="Keine Bilder in dieser Gruppe." /> diff --git a/frontend/src/services/reorderService.js b/frontend/src/services/reorderService.js index 815aed5..9e1dc37 100644 --- a/frontend/src/services/reorderService.js +++ b/frontend/src/services/reorderService.js @@ -1,10 +1,37 @@ -import { sendRequest } from './sendRequest'; - /** * Service für Drag-and-Drop Reordering von Bildern */ class ReorderService { + /** + * Internal HTTP request helper + * @param {string} url - API endpoint URL + * @param {string} method - HTTP method (GET, POST, PUT, DELETE) + * @param {Object} data - Request body data + * @returns {Promise} API response + */ + async makeRequest(url, method = 'GET', data = null) { + const options = { + method, + headers: { + 'Content-Type': 'application/json', + }, + }; + + if (data) { + options.body = JSON.stringify(data); + } + + const response = await fetch(url, options); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP ${response.status}: ${errorText}`); + } + + return await response.json(); + } + /** * Reorder images within a group * @param {string} groupId - The group ID @@ -21,7 +48,7 @@ class ReorderService { } try { - const response = await sendRequest(`/api/groups/${groupId}/reorder`, 'PUT', { + const response = await this.makeRequest(`/api/groups/${groupId}/reorder`, 'PUT', { imageIds: imageIds }); @@ -79,4 +106,13 @@ class ReorderService { } } -export default new ReorderService(); \ No newline at end of file +// Create and export service instance +const reorderService = new ReorderService(); + +export default reorderService; + +// Named exports for easier testing +export const updateImageOrder = reorderService.updateImageOrder.bind(reorderService); +export const validateImageIds = reorderService.validateImageIds.bind(reorderService); +export const extractImageIds = reorderService.extractImageIds.bind(reorderService); +export const reorderArray = reorderService.reorderArray.bind(reorderService); \ No newline at end of file