'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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; 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 { Switch } from '@/components/ui/switch'; import { Plus, Edit, Trash2, Clock } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { getWeekDays } from '@/lib/utils'; interface TimeSlot { id: string; dayOfWeek: number; startTime: string; endTime: string; isActive: boolean; createdAt: string; updatedAt: string; } // Use Irish week order (Monday first) const DAYS = getWeekDays().map((day) => day.label); const IRISH_DAY_ORDER = [1, 2, 3, 4, 5, 6, 0]; // Monday-Sunday in JS getDay() values export function AdminTimeSlotManagement() { const [timeSlots, setTimeSlots] = useState([]); const [loading, setLoading] = useState(false); const [showDialog, setShowDialog] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [showWipeDayDialog, setShowWipeDayDialog] = useState(false); const [editingSlot, setEditingSlot] = useState(null); const [slotToDelete, setSlotToDelete] = useState(null); const [dayToWipe, setDayToWipe] = useState(null); const [formData, setFormData] = useState({ dayOfWeek: 1, // Default to Monday (Irish standard) startTime: '', endTime: '', isActive: true, }); const { toast } = useToast(); useEffect(() => { fetchTimeSlots(); }, []); const fetchTimeSlots = async () => { try { setLoading(true); const response = await fetch('/api/admin/time-slots'); if (response.ok) { const data = await response.json(); setTimeSlots(data.timeSlots); } else { toast({ title: 'Error', description: 'Failed to fetch time slots', variant: 'destructive', }); } } catch (error) { console.error('Error fetching time slots:', error); toast({ title: 'Error', description: 'Failed to fetch time slots', variant: 'destructive', }); } finally { setLoading(false); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { setLoading(true); const url = editingSlot ? `/api/admin/time-slots/${editingSlot.id}` : '/api/admin/time-slots'; const method = editingSlot ? 'PUT' : 'POST'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formData), }); if (response.ok) { toast({ title: 'Success', description: editingSlot ? 'Time slot updated successfully' : 'Time slot created successfully', }); fetchTimeSlots(); setShowDialog(false); resetForm(); } else { const error = await response.json(); toast({ title: 'Error', description: error.error || 'Failed to save time slot', variant: 'destructive', }); } } catch (error) { console.error('Error saving time slot:', error); toast({ title: 'Error', description: 'Failed to save time slot', variant: 'destructive', }); } finally { setLoading(false); } }; const openDeleteDialog = (slot: TimeSlot) => { setSlotToDelete(slot); setShowDeleteDialog(true); }; const confirmDeleteSlot = async () => { if (slotToDelete) { await handleDelete(slotToDelete.id); setShowDeleteDialog(false); setSlotToDelete(null); } }; const handleDelete = async (id: string) => { try { setLoading(true); const response = await fetch(`/api/admin/time-slots/${id}`, { method: 'DELETE', }); if (response.ok) { toast({ title: 'Success', description: 'Time slot deleted successfully', }); fetchTimeSlots(); } else { const error = await response.json(); toast({ title: 'Error', description: error.error || 'Failed to delete time slot', variant: 'destructive', }); } } catch (error) { console.error('Error deleting time slot:', error); toast({ title: 'Error', description: 'Failed to delete time slot', variant: 'destructive', }); } finally { setLoading(false); } }; const openWipeDayDialog = (dayOfWeek: number) => { setDayToWipe(dayOfWeek); setShowWipeDayDialog(true); }; const confirmWipeDay = async () => { if (dayToWipe !== null) { await handleWipeDay(dayToWipe); setShowWipeDayDialog(false); setDayToWipe(null); } }; const handleWipeDay = async (dayOfWeek: number) => { try { setLoading(true); const dayName = DAYS[dayOfWeek]; const slotsToDelete = timeSlots.filter((slot) => slot.dayOfWeek === dayOfWeek); // Delete all slots for this day const deletePromises = slotsToDelete.map((slot) => fetch(`/api/admin/time-slots/${slot.id}`, { method: 'DELETE', }) ); const responses = await Promise.all(deletePromises); const successCount = responses.filter((response) => response.ok).length; if (successCount === slotsToDelete.length) { toast({ title: 'Success', description: `All ${dayName} time slots deleted successfully`, }); fetchTimeSlots(); } else { toast({ title: 'Partial Success', description: `${successCount} of ${slotsToDelete.length} slots deleted`, variant: 'destructive', }); } } catch (error) { console.error('Error wiping day slots:', error); toast({ title: 'Error', description: 'Failed to delete day slots', variant: 'destructive', }); } finally { setLoading(false); } }; const handleEdit = (slot: TimeSlot) => { setEditingSlot(slot); setFormData({ dayOfWeek: slot.dayOfWeek, startTime: slot.startTime, endTime: slot.endTime, isActive: slot.isActive, }); setShowDialog(true); }; const resetForm = () => { setEditingSlot(null); setFormData({ dayOfWeek: 1, // Default to Monday (Irish standard) startTime: '', endTime: '', isActive: true, }); }; const groupedTimeSlots = timeSlots.reduce((acc, slot) => { if (!acc[slot.dayOfWeek]) { acc[slot.dayOfWeek] = []; } acc[slot.dayOfWeek].push(slot); return acc; }, {} as Record); return (
Time Slot Management {editingSlot ? 'Edit Time Slot' : 'Add New Time Slot'}
setFormData({ ...formData, startTime: e.target.value })} required />
setFormData({ ...formData, endTime: e.target.value })} required />
setFormData({ ...formData, isActive: checked })} />
{loading && timeSlots.length === 0 ? (
Loading time slots...
) : (
{IRISH_DAY_ORDER.map((jsDayOfWeek, displayIndex) => { const dayName = DAYS[displayIndex]; return (

{dayName}

{groupedTimeSlots[jsDayOfWeek]?.length > 0 && ( )}
{groupedTimeSlots[jsDayOfWeek]?.length > 0 ? (
{groupedTimeSlots[jsDayOfWeek] .sort((a, b) => a.startTime.localeCompare(b.startTime)) .map((slot) => (
{slot.startTime} - {slot.endTime}
{slot.isActive ? 'Active' : 'Inactive'}
))}
) : (

No time slots configured for {dayName}

)}
); })}
)}
{/* Delete Time Slot Dialog */} Are you sure? Are you sure you want to delete this time slot? This action cannot be undone. Cancel Delete {/* Wipe Day Dialog */} Are you sure? Are you sure you want to delete ALL time slots for{' '} {dayToWipe !== null ? DAYS[dayToWipe] : 'this day'}? This action cannot be undone. Cancel Delete All
); }