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:
parent
c0ef92ec23
commit
15fc02235f
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user