import React from 'react'; import { format, addHours, isToday } from 'date-fns'; interface CalendarEvent { id: string; title: string; start: Date; end: Date; type: 'task' | 'event'; color?: string; } interface CalendarDayViewProps { currentDate: Date; events: CalendarEvent[]; onEventClick?: (event: CalendarEvent) => void; onTimeSlotClick?: (date: Date, hour: number) => void; onEventDrop?: (eventId: string, newDate: Date, newHour: number) => void; } const CalendarDayView: React.FC = ({ currentDate, events, onEventClick, onTimeSlotClick, onEventDrop, }) => { const hours = Array.from({ length: 24 }, (_, i) => i); const [draggedEventId, setDraggedEventId] = React.useState( null ); 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 }; const handleDragStart = (event: CalendarEvent, e: React.DragEvent) => { e.stopPropagation(); setDraggedEventId(event.id); e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', event.id); }; const handleDragEnd = () => { setDraggedEventId(null); }; const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }; const handleDrop = (hour: number, e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); const eventId = e.dataTransfer.getData('text/plain'); if (eventId && onEventDrop) { onEventDrop(eventId, currentDate, hour); } setDraggedEventId(null); }; return (
{/* Header */}
{format(currentDate, 'EEEE')}
{isToday(currentDate) ? ( {format(currentDate, 'd')} ) : ( 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' ); const duration = event.end.getTime() - event.start.getTime(); return ( eventDay === currentDay && duration >= 24 * 60 * 60 * 1000 ); }) .map((event) => (
handleEventClick(event, e)} className={`text-sm px-3 py-2 rounded-lg text-white cursor-pointer hover:scale-[1.01] hover:shadow-md transition-all duration-200 font-medium ${ event.type === 'task' ? 'border-l-3 border-l-white/60' : '' }`} style={{ backgroundColor: event.color || '#3b82f6', boxShadow: '0 2px 4px rgba(0,0,0,0.1)', }} title={event.title} > {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)} onDragOver={handleDragOver} onDrop={(e) => handleDrop(hour, e)} className="flex-1 min-h-[60px] cursor-pointer hover:bg-blue-50/40 dark:hover:bg-blue-900/10 relative transition-colors duration-150 bg-white dark:bg-gray-900" > {timeSlotEvents.map((event, index) => { const eventCount = timeSlotEvents.length; const widthPercentage = eventCount > 1 ? 100 / eventCount - 2 : 100; const leftOffset = eventCount > 1 ? (100 / eventCount) * index : 0; return (
handleDragStart(event, e) } onDragEnd={handleDragEnd} onClick={(e) => handleEventClick(event, e) } className={`absolute text-sm px-3 py-2 rounded-lg text-white transition-all duration-200 z-10 font-medium ${ event.type === 'task' ? 'border-l-3 border-l-white/60 cursor-move hover:scale-[1.01] hover:shadow-lg' : 'cursor-pointer' } ${draggedEventId === event.id ? 'opacity-50' : ''}`} style={{ backgroundColor: event.color || '#3b82f6', top: calculateEventPosition( event ), height: calculateEventHeight( event ), left: `calc(0.5rem + ${leftOffset}%)`, width: `${widthPercentage}%`, boxShadow: '0 3px 6px rgba(0,0,0,0.15)', }} title={`${event.title} - ${format(event.start, 'HH:mm')} to ${format(event.end, 'HH:mm')}`} >
{event.title}
{format( event.start, 'HH:mm' )}{' '} -{' '} {format(event.end, 'HH:mm')}
); })}
); })}
); }; export default CalendarDayView;