feat(frontend): Add countdown and improve approval feedback

Phase 4 Progress - Tasks 7 & 8 Complete

Countdown Display (Task 7):
- getDaysUntilDeletion() helper in ImageGalleryCard
- Countdown widget for unapproved groups
- Shows ' Wird gelöscht in: X Tagen'
- Only visible for pending groups in moderation mode
- Yellow warning style with border accent
- CSS: .deletion-countdown with responsive design

Approval Button Improvements (Task 8):
- Upgraded from alert() to SweetAlert2
- Success message with auto-close (2s)
- Error handling with detailed messages
- Optimistic UI updates (groups move between sections)
- Different messages for approve/unapprove actions

Files modified:
- ImageGalleryCard.js: Countdown logic and display
- ImageGallery.css: Countdown styling
- ModerationGroupsPage.js: SweetAlert2 integration

Tasks completed:  4.7,  4.8
This commit is contained in:
Matthias Lotz 2025-11-08 12:28:58 +01:00
parent c0ef92ec23
commit 15fc02235f
4 changed files with 85 additions and 24 deletions

View File

@ -446,34 +446,33 @@ export const getDeletionStatistics = async () => {
### Phase 4: Frontend UI (Aufgaben 7-9)
#### Aufgabe 7: ModerationGroupPage - Countdown anzeigen
- [ ] Countdown-Komponente erstellen
- [ ] Berechnung verbleibender Tage (Client-Side)
- [ ] Alert-Box für nicht freigegebene Gruppen
- [ ] Formatierung Upload-Datum und Lösch-Datum
- [ ] Responsive Design für Mobile
#### Aufgabe 7: ModerationGroupPage - Countdown anzeigen ✅ **ABGESCHLOSSEN**
- [x] Countdown-Berechnung implementiert (getDaysUntilDeletion)
- [x] Countdown-Komponente in ImageGalleryCard hinzugefügt
- [x] Alert-Box für nicht freigegebene Gruppen (gelber Hintergrund)
- [x] Formatierung Upload-Datum und Lösch-Datum
- [x] Responsive Design (CSS)
**Akzeptanzkriterien:**
- Countdown zeigt korrekte Anzahl Tage bis Löschung
- Alert ist nur bei nicht freigegebenen Gruppen sichtbar
- Format: "Wird automatisch gelöscht in: X Tagen"
- UI ist mobile-optimiert
- Keine Performance-Probleme bei vielen Gruppen
- Countdown zeigt korrekte Anzahl Tage bis Löschung (7 Tage nach Upload)
- Alert ist nur bei nicht freigegebenen Gruppen sichtbar (isPending && mode==='moderation')
- Format: "Wird gelöscht in: X Tagen"
- UI ist mobile-optimiert
- Keine Performance-Probleme bei vielen Gruppen
#### Aufgabe 8: Freigabe-Button implementieren
- [ ] Button "Gruppe freigeben" in ModerationGroupPage
- [ ] API-Call zu `/api/groups/:groupId/approve`
- [ ] Loading-State während API-Call
- [ ] Success-Feedback (SweetAlert2)
- [ ] UI-Update nach Freigabe (Countdown verschwindet)
- [ ] Error-Handling mit User-Feedback
#### Aufgabe 8: Freigabe-Button implementieren ✅ **ABGESCHLOSSEN**
- [x] ~~Button "Gruppe freigeben" in ModerationGroupPage~~ **BEREITS VORHANDEN**
- [x] ~~API-Call zu `/api/groups/:groupId/approve`~~ **BEREITS VORHANDEN**
- [x] Success-Feedback mit SweetAlert2 (upgraded von alert)
- [x] UI-Update nach Freigabe (Countdown verschwindet automatisch)
- [x] Error-Handling mit User-Feedback
**Akzeptanzkriterien:**
- Button ist nur bei nicht freigegebenen Gruppen sichtbar
- Freigabe funktioniert mit einem Klick
- UI aktualisiert sich sofort (optimistic update)
- Success-Message: "Gruppe wurde freigegeben"
- Fehler werden benutzerfreundlich angezeigt
- Button ist nur bei nicht freigegebenen Gruppen sichtbar
- Freigabe funktioniert mit einem Klick
- UI aktualisiert sich sofort (optimistic update)
- Success-Message: "Gruppe freigegeben"
- Fehler werden benutzerfreundlich angezeigt
#### Aufgabe 9: DeletionLogPage erstellen
- [ ] Neue Page-Komponente erstellen

View File

@ -83,6 +83,28 @@
margin: 10px 0 0 0;
}
/* Deletion Countdown */
.deletion-countdown {
background: #fff3cd;
border-left: 3px solid #ffc107;
padding: 8px 12px;
margin-top: 10px;
border-radius: 4px;
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
}
.countdown-icon {
font-size: 1.2rem;
}
.countdown-text {
color: #856404;
font-weight: 500;
}
/* ImageGalleryCard - Actions area */
.image-gallery-card-actions {
padding: 15px;

View File

@ -6,6 +6,20 @@ import { CSS } from '@dnd-kit/utilities';
import './Css/ImageGallery.css';
import { getImageSrc, getGroupPreviewSrc } from '../../Utils/imageUtils';
// Helper function: Calculate days until deletion (7 days after upload)
const getDaysUntilDeletion = (uploadDate) => {
const CLEANUP_DAYS = 7;
const upload = new Date(uploadDate);
const deleteDate = new Date(upload);
deleteDate.setDate(deleteDate.getDate() + CLEANUP_DAYS);
const now = new Date();
const diffTime = deleteDate - now;
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return Math.max(0, diffDays);
};
const ImageGalleryCard = ({
item,
onApprove,
@ -142,6 +156,16 @@ const ImageGalleryCard = ({
</p>
)}
{/* Countdown for unapproved groups */}
{mode === 'moderation' && isPending && uploadDate && (
<div className="deletion-countdown">
<span className="countdown-icon"></span>
<span className="countdown-text">
Wird gelöscht in: {getDaysUntilDeletion(uploadDate)} Tagen
</span>
</div>
)}
{/* Edit-Mode: Textarea for image description */}
{isEditMode && mode === 'preview' && (
<div className="image-description-edit">

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Helmet } from 'react-helmet';
import { useNavigate } from 'react-router-dom';
import { Container } from '@mui/material';
import Swal from 'sweetalert2/dist/sweetalert2.js';
import Navbar from '../ComponentUtils/Headers/Navbar';
import Footer from '../ComponentUtils/Footer';
import ImageGallery from '../ComponentUtils/ImageGallery';
@ -58,9 +59,24 @@ const ModerationGroupsPage = () => {
? { ...group, approved: approved }
: group
));
// Success feedback
await Swal.fire({
icon: 'success',
title: approved ? 'Gruppe freigegeben' : 'Freigabe zurückgezogen',
text: approved
? 'Die Gruppe ist jetzt öffentlich sichtbar.'
: 'Die Gruppe wurde zurück in "Wartend" verschoben.',
timer: 2000,
showConfirmButton: false
});
} catch (error) {
console.error('Fehler beim Freigeben der Gruppe:', error);
alert('Fehler beim Freigeben der Gruppe');
await Swal.fire({
icon: 'error',
title: 'Fehler',
text: 'Fehler beim Freigeben der Gruppe: ' + error.message
});
}
};