import React from 'react'; import { format, addHours, isToday } from 'date-fns'; interface CalendarEvent { id: string; title: string; start: Date; end: Date; type: 'task' | 'event' | 'google'; color?: string; } interface CalendarDayViewProps { currentDate: Date; events: CalendarEvent[]; onEventClick?: (event: CalendarEvent) => void; onTimeSlotClick?: (date: Date, hour: number) => void; } const CalendarDayView: React.FC = ({ currentDate, events, onEventClick, onTimeSlotClick, }) => { const hours = Array.from({ length: 24 }, (_, i) => i); const getEventsForTimeSlot = (hour: number) => { return events.filter((event) => { const eventDay = format(event.start, 'yyyy-MM-dd'); const currentDay = format(currentDate, 'yyyy-MM-dd'); const eventHour = event.start.getHours(); return eventDay === currentDay && eventHour === hour; }); }; const handleTimeSlotClick = (hour: number) => { if (onTimeSlotClick) { onTimeSlotClick(currentDate, hour); } }; const handleEventClick = (event: CalendarEvent, e: React.MouseEvent) => { e.stopPropagation(); if (onEventClick) { onEventClick(event); } }; const calculateEventHeight = (event: CalendarEvent) => { const durationMs = event.end.getTime() - event.start.getTime(); const durationHours = durationMs / (1000 * 60 * 60); return Math.max(durationHours * 48, 24); // Minimum 24px height }; const calculateEventPosition = (event: CalendarEvent) => { const minutes = event.start.getMinutes(); return (minutes / 60) * 48; // 48px per hour }; return (
{/* Header */}
{format(currentDate, 'EEEE')}
{format(currentDate, 'd')}
{format(currentDate, 'MMMM yyyy')}
{/* All day events */}
All day
{events .filter((event) => { const eventDay = format(event.start, 'yyyy-MM-dd'); const currentDay = format( currentDate, 'yyyy-MM-dd' ); // Check if it's an all-day event (spans 24 hours or more) const duration = event.end.getTime() - event.start.getTime(); return ( eventDay === currentDay && duration >= 24 * 60 * 60 * 1000 ); }) .map((event) => (
handleEventClick(event, e)} className={`text-xs p-2 rounded text-white cursor-pointer hover:opacity-80 transition-opacity ${ event.type === 'task' ? 'border-l-2 border-l-white/50' : '' }`} style={{ backgroundColor: event.color || '#3b82f6', }} title={`${event.type === 'task' ? '📋 ' : ''}${event.title}`} > {event.type === 'task' && '📋 '} {event.title}
))}
{/* Time slots */}
{hours.map((hour) => { const timeSlotEvents = getEventsForTimeSlot(hour); return (
{/* Time column */}
{format( addHours( new Date().setHours(hour, 0, 0, 0), 0 ), 'HH:mm' )}
{/* Event area */}
handleTimeSlotClick(hour)} className="flex-1 h-12 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 relative" > {timeSlotEvents.map((event) => (
handleEventClick(event, e) } className={`absolute left-1 right-1 text-xs p-1 rounded text-white cursor-pointer hover:opacity-80 transition-opacity z-10 ${ event.type === 'task' ? 'border-l-2 border-l-white/50' : '' }`} style={{ backgroundColor: event.color || '#3b82f6', top: calculateEventPosition( event ), height: calculateEventHeight( event ), }} title={`${event.type === 'task' ? '📋 ' : ''}${event.title} - ${format(event.start, 'HH:mm')} to ${format(event.end, 'HH:mm')}`} >
{event.type === 'task' && '📋 '} {event.title}
{format(event.start, 'HH:mm')} -{' '} {format(event.end, 'HH:mm')}
))}
); })}
); }; export default CalendarDayView;