'use client'; import { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; import { Textarea } from '@/components/ui/textarea'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { useToast } from '@/hooks/use-toast'; import { Megaphone, Plus, Edit, Trash2, Calendar, AlertCircle, CheckCircle, Clock } from 'lucide-react'; interface Announcement { id: string; title: string; content: string; priority: 'low' | 'medium' | 'high'; isActive: boolean; expiresAt?: string; createdAt: string; updatedAt: string; } interface AnnouncementFormData { title: string; content: string; priority: 'low' | 'medium' | 'high'; isActive: boolean; expiresAt: string; } export function AdminAnnouncementManagement() { const [announcements, setAnnouncements] = useState([]); const [loading, setLoading] = useState(true); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isEditDialogOpen, setIsEditDialogOpen] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [editingAnnouncement, setEditingAnnouncement] = useState(null); const [announcementToDelete, setAnnouncementToDelete] = useState(null); const [formData, setFormData] = useState({ title: '', content: '', priority: 'medium', isActive: true, expiresAt: '', }); const { toast } = useToast(); useEffect(() => { fetchAnnouncements(); }, []); const fetchAnnouncements = async () => { try { setLoading(true); const response = await fetch('/api/admin/announcements'); if (response.ok) { const data = await response.json(); setAnnouncements(data.announcements); } else { throw new Error('Failed to fetch announcements'); } } catch (error) { console.error('Error fetching announcements:', error); toast({ title: 'Error', description: 'Failed to fetch announcements', variant: 'destructive', }); } finally { setLoading(false); } }; const handleCreateAnnouncement = async () => { try { if (!formData.title || !formData.content) { toast({ title: 'Error', description: 'Please fill in title and content', variant: 'destructive', }); return; } const submitData = { ...formData, expiresAt: formData.expiresAt || null, }; const response = await fetch('/api/admin/announcements', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(submitData), }); const data = await response.json(); if (response.ok) { toast({ title: 'Success', description: 'Announcement created successfully', }); setIsCreateDialogOpen(false); resetForm(); fetchAnnouncements(); } else { toast({ title: 'Error', description: data.error || 'Failed to create announcement', variant: 'destructive', }); } } catch (error) { console.error('Error creating announcement:', error); toast({ title: 'Error', description: 'Failed to create announcement', variant: 'destructive', }); } }; const handleEditAnnouncement = async () => { try { if (!editingAnnouncement || !formData.title || !formData.content) { toast({ title: 'Error', description: 'Please fill in title and content', variant: 'destructive', }); return; } const submitData = { ...formData, expiresAt: formData.expiresAt || null, }; const response = await fetch(`/api/admin/announcements/${editingAnnouncement.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(submitData), }); const data = await response.json(); if (response.ok) { toast({ title: 'Success', description: 'Announcement updated successfully', }); setIsEditDialogOpen(false); setEditingAnnouncement(null); resetForm(); fetchAnnouncements(); } else { toast({ title: 'Error', description: data.error || 'Failed to update announcement', variant: 'destructive', }); } } catch (error) { console.error('Error updating announcement:', error); toast({ title: 'Error', description: 'Failed to update announcement', variant: 'destructive', }); } }; const openDeleteDialog = (announcement: Announcement) => { setAnnouncementToDelete(announcement); setIsDeleteDialogOpen(true); }; const confirmDeleteAnnouncement = async () => { if (announcementToDelete) { await handleDeleteAnnouncement(announcementToDelete.id); setIsDeleteDialogOpen(false); setAnnouncementToDelete(null); } }; const handleDeleteAnnouncement = async (announcementId: string) => { try { const response = await fetch(`/api/admin/announcements/${announcementId}`, { method: 'DELETE', }); const data = await response.json(); if (response.ok) { toast({ title: 'Success', description: 'Announcement deleted successfully', }); fetchAnnouncements(); } else { toast({ title: 'Error', description: data.error || 'Failed to delete announcement', variant: 'destructive', }); } } catch (error) { console.error('Error deleting announcement:', error); toast({ title: 'Error', description: 'Failed to delete announcement', variant: 'destructive', }); } }; const openEditDialog = (announcement: Announcement) => { setEditingAnnouncement(announcement); setFormData({ title: announcement.title, content: announcement.content, priority: announcement.priority, isActive: announcement.isActive, expiresAt: announcement.expiresAt ? announcement.expiresAt.split('T')[0] : '', }); setIsEditDialogOpen(true); }; const resetForm = () => { setFormData({ title: '', content: '', priority: 'medium', isActive: true, expiresAt: '', }); }; const getPriorityColor = (priority: string) => { switch (priority) { case 'high': return 'text-destructive bg-destructive/10 dark:bg-destructive/20'; case 'medium': return 'text-amber-600 bg-amber-50 dark:text-amber-400 dark:bg-amber-950/50'; case 'low': return 'text-green-600 bg-green-50 dark:text-green-400 dark:bg-green-950/50'; default: return 'text-muted-foreground bg-muted'; } }; const getPriorityIcon = (priority: string) => { switch (priority) { case 'high': return ; case 'medium': return ; case 'low': return ; default: return ; } }; const isExpired = (expiresAt?: string) => { if (!expiresAt) return false; return new Date(expiresAt) < new Date(); }; if (loading) { return (
); } return (
{/* Header */}

Announcement Management

Create New Announcement
setFormData({ ...formData, title: e.target.value })} placeholder='Announcement title' />