initial version of the app
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user