'use client' import { useState, useCallback, useMemo } from 'react' import { Calendar, momentLocalizer, View, Views } from 'react-big-calendar' import moment from 'moment' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { CalendarIcon, Clock, User, MapPin, DollarSign } from 'lucide-react' import { cn } from '@/lib/utils' import 'react-big-calendar/lib/css/react-big-calendar.css' // Setup the localizer for react-big-calendar const localizer = momentLocalizer(moment) interface CalendarEvent { id: string title: string start: Date end: Date resource: { appointmentId: string artistId: string artistName: string clientId: string clientName: string clientEmail: string status: 'PENDING' | 'CONFIRMED' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED' depositAmount?: number totalAmount?: number notes?: string description?: string } } interface AppointmentCalendarProps { appointments: any[] artists: any[] onEventSelect?: (event: CalendarEvent) => void onSlotSelect?: (slotInfo: { start: Date; end: Date; slots: Date[] }) => void onEventUpdate?: (eventId: string, updates: any) => void className?: string } const statusColors = { PENDING: 'bg-yellow-100 border-yellow-300 text-yellow-800', CONFIRMED: 'bg-blue-100 border-blue-300 text-blue-800', IN_PROGRESS: 'bg-green-100 border-green-300 text-green-800', COMPLETED: 'bg-gray-100 border-gray-300 text-gray-800', CANCELLED: 'bg-red-100 border-red-300 text-red-800', } export function AppointmentCalendar({ appointments, artists, onEventSelect, onSlotSelect, onEventUpdate, className }: AppointmentCalendarProps) { const [view, setView] = useState(Views.WEEK) const [date, setDate] = useState(new Date()) const [selectedArtist, setSelectedArtist] = useState('all') const [selectedEvent, setSelectedEvent] = useState(null) // Convert appointments to calendar events const events = useMemo(() => { const filteredAppointments = selectedArtist === 'all' ? appointments : appointments.filter(apt => apt.artist_id === selectedArtist) return filteredAppointments.map(appointment => ({ id: appointment.id, title: `${appointment.title} - ${appointment.client_name}`, start: new Date(appointment.start_time), end: new Date(appointment.end_time), resource: { appointmentId: appointment.id, artistId: appointment.artist_id, artistName: appointment.artist_name, clientId: appointment.client_id, clientName: appointment.client_name, clientEmail: appointment.client_email, status: appointment.status, depositAmount: appointment.deposit_amount, totalAmount: appointment.total_amount, notes: appointment.notes, description: appointment.description, } })) as CalendarEvent[] }, [appointments, selectedArtist]) // Custom event style getter const eventStyleGetter = useCallback((event: CalendarEvent) => { const status = event.resource.status const baseStyle = { borderRadius: '4px', border: '1px solid', fontSize: '12px', padding: '2px 4px', } switch (status) { case 'PENDING': return { style: { ...baseStyle, backgroundColor: '#fef3c7', borderColor: '#fcd34d', color: '#92400e', } } case 'CONFIRMED': return { style: { ...baseStyle, backgroundColor: '#dbeafe', borderColor: '#60a5fa', color: '#1e40af', } } case 'IN_PROGRESS': return { style: { ...baseStyle, backgroundColor: '#dcfce7', borderColor: '#4ade80', color: '#166534', } } case 'COMPLETED': return { style: { ...baseStyle, backgroundColor: '#f3f4f6', borderColor: '#9ca3af', color: '#374151', } } case 'CANCELLED': return { style: { ...baseStyle, backgroundColor: '#fee2e2', borderColor: '#f87171', color: '#991b1b', } } default: return { style: baseStyle } } }, []) const handleSelectEvent = useCallback((event: CalendarEvent) => { setSelectedEvent(event) onEventSelect?.(event) }, [onEventSelect]) const handleSelectSlot = useCallback((slotInfo: { start: Date; end: Date; slots: Date[] }) => { onSlotSelect?.(slotInfo) }, [onSlotSelect]) const handleStatusUpdate = useCallback((eventId: string, newStatus: string) => { onEventUpdate?.(eventId, { status: newStatus }) setSelectedEvent(null) }, [onEventUpdate]) const formatCurrency = (amount?: number) => { if (!amount) return 'N/A' return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount) } return (
{/* Calendar Controls */}

Appointment Calendar

{/* Calendar */}
`+${total} more`, }} />
{/* Event Details Dialog */} setSelectedEvent(null)}> Appointment Details {selectedEvent && (

{selectedEvent.resource.clientName}

{selectedEvent.resource.clientEmail}

{selectedEvent.resource.artistName}
{moment(selectedEvent.start).format('MMM D, h:mm A')}
{selectedEvent.resource.status}
{selectedEvent.resource.description && (

Description

{selectedEvent.resource.description}

)} {(selectedEvent.resource.depositAmount || selectedEvent.resource.totalAmount) && (
Deposit:

{formatCurrency(selectedEvent.resource.depositAmount)}

Total:

{formatCurrency(selectedEvent.resource.totalAmount)}

)} {selectedEvent.resource.notes && (

Notes

{selectedEvent.resource.notes}

)} {/* Status Update Buttons */}
)}
) }