// DeadlinesCalendarWidget - Monthly calendar showing project deadlines and Google events function DeadlinesCalendarWidget({ projects, onViewChange, googleEvents = [], onMonthChange }) { const [currentDate, setCurrentDate] = React.useState(new Date()); const [selectedDay, setSelectedDay] = React.useState(null); // Italian month names const monthNames = [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ]; // Italian weekday abbreviations (starting Monday) const weekDays = ['Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom']; // Generate calendar days for current month const calendarDays = React.useMemo(() => { const year = currentDate.getFullYear(); const month = currentDate.getMonth(); const firstDay = new Date(year, month, 1); const lastDay = new Date(year, month + 1, 0); // Get day of week (0=Sun, adjust for Monday start) let startPadding = firstDay.getDay() - 1; if (startPadding < 0) startPadding = 6; // Sunday becomes 6 const daysInMonth = lastDay.getDate(); const days = []; // Add padding for previous month for (let i = startPadding - 1; i >= 0; i--) { const prevDate = new Date(year, month, -i); days.push({ date: prevDate, isCurrentMonth: false }); } // Current month days for (let d = 1; d <= daysInMonth; d++) { days.push({ date: new Date(year, month, d), isCurrentMonth: true }); } // Pad to complete grid (6 rows x 7 days = 42) const remaining = 42 - days.length; for (let i = 1; i <= remaining; i++) { days.push({ date: new Date(year, month + 1, i), isCurrentMonth: false }); } return days; }, [currentDate]); // Get projects for a specific date const getProjectsForDate = React.useCallback((date) => { const dateStr = date.toISOString().split('T')[0]; return projects.filter(p => p.due_date === dateStr && p.status !== 'completato' && !p.is_archived ); }, [projects]); // Get Google events for a specific date const getGoogleEventsForDate = React.useCallback((date) => { const dateStr = date.toISOString().split('T')[0]; return googleEvents.filter(event => { // Handle all-day events (start is just a date) if (event.all_day) { return event.start === dateStr; } // Handle timed events (start is a datetime string) const eventDate = event.start?.split('T')[0]; return eventDate === dateStr; }); }, [googleEvents]); // Check if date is today const isToday = (date) => { const today = new Date(); return date.getDate() === today.getDate() && date.getMonth() === today.getMonth() && date.getFullYear() === today.getFullYear(); }; // Navigate months const goToPrevMonth = () => { const newDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1); setCurrentDate(newDate); setSelectedDay(null); if (onMonthChange) { onMonthChange(newDate.getMonth() + 1, newDate.getFullYear()); } }; const goToNextMonth = () => { const newDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1); setCurrentDate(newDate); setSelectedDay(null); if (onMonthChange) { onMonthChange(newDate.getMonth() + 1, newDate.getFullYear()); } }; const goToToday = () => { const newDate = new Date(); setCurrentDate(newDate); setSelectedDay(null); if (onMonthChange) { onMonthChange(newDate.getMonth() + 1, newDate.getFullYear()); } }; // Get dot color based on priority const getDotColor = (priority) => { switch (priority) { case 'high': return 'bg-red-500'; case 'medium': return 'bg-amber-500'; case 'low': return 'bg-blue-500'; default: return 'bg-slate-400'; } }; // Render dots for projects and Google events on a day const renderDots = (dayProjects, dayGoogleEvents) => { const totalItems = dayProjects.length + dayGoogleEvents.length; if (totalItems === 0) return null; const maxDots = 3; const dots = []; // Add project dots first dayProjects.slice(0, maxDots).forEach((p, i) => { dots.push( ); }); // Add Google event dots (blue-400 color) const remainingSlots = maxDots - dots.length; dayGoogleEvents.slice(0, remainingSlots).forEach((e, i) => { dots.push( ); }); const extraCount = totalItems - maxDots; return (