Files
tt-booking/components/announcements/announcements-list.tsx
T
2025-09-21 17:11:02 +01:00

124 lines
3.5 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Bell, Info, AlertTriangle, AlertCircle } from 'lucide-react';
interface Announcement {
id: string;
title: string;
content: string;
priority: 'low' | 'medium' | 'high';
isActive: boolean;
expiresAt?: string;
createdAt: string;
}
export function AnnouncementsList() {
const [announcements, setAnnouncements] = useState<Announcement[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchAnnouncements();
}, []);
const fetchAnnouncements = async () => {
try {
setLoading(true);
const response = await fetch('/api/admin/announcements');
if (response.ok) {
const data = await response.json();
// Filter to show only active, non-expired announcements
const activeAnnouncements = data.announcements.filter((announcement: Announcement) => {
if (!announcement.isActive) return false;
if (announcement.expiresAt && new Date(announcement.expiresAt) < new Date()) return false;
return true;
});
setAnnouncements(activeAnnouncements);
}
} catch (error) {
console.error('Error fetching announcements:', error);
// Fallback to default announcements if API fails
setAnnouncements([
{
id: '1',
title: 'Welcome to Table Tennis Booking!',
content:
'Book your favorite court slots up to 7 days in advance. Remember to arrive 5 minutes early for your booking.',
priority: 'medium',
isActive: true,
createdAt: new Date().toISOString(),
},
]);
} finally {
setLoading(false);
}
};
const getPriorityIcon = (priority: string) => {
switch (priority) {
case 'high':
return <AlertCircle className='h-4 w-4 text-red-500' />;
case 'medium':
return <AlertTriangle className='h-4 w-4 text-yellow-500' />;
default:
return <Info className='h-4 w-4 text-blue-500' />;
}
};
const getPriorityColor = (priority: string) => {
switch (priority) {
case 'high':
return 'bg-red-100 text-red-800 border-red-200';
case 'medium':
return 'bg-yellow-100 text-yellow-800 border-yellow-200';
default:
return 'bg-blue-100 text-blue-800 border-blue-200';
}
};
return (
<Card>
<CardHeader>
<CardTitle className='flex items-center gap-2'>
<Bell className='h-5 w-5' />
Announcements
</CardTitle>
</CardHeader>
<CardContent>
<div className='space-y-4'>
{announcements
.filter((a) => a.isActive)
.map((announcement) => (
<div key={announcement.id} className='p-4 border rounded-lg bg-gray-50'>
<div className='flex items-start justify-between gap-3'>
<div className='flex items-start gap-2 flex-1'>
{getPriorityIcon(announcement.priority)}
<div className='space-y-1'>
<h4 className='font-medium text-sm'>{announcement.title}</h4>
<p className='text-sm text-gray-600'>{announcement.content}</p>
</div>
</div>
<Badge
variant='outline'
className={`text-xs ${getPriorityColor(announcement.priority)}`}
>
{announcement.priority}
</Badge>
</div>
</div>
))}
{announcements.filter((a) => a.isActive).length === 0 && (
<div className='text-center py-8 text-gray-500'>
<Bell className='h-8 w-8 mx-auto mb-2 opacity-30' />
<p>No announcements at this time</p>
</div>
)}
</div>
</CardContent>
</Card>
);
}