'use client'; import { useEffect, useState, useMemo, Suspense } from 'react'; import { Filter } from 'lucide-react'; import dynamic from 'next/dynamic'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Checkbox } from '@/components/ui/checkbox'; import { Label } from '@/components/ui/label'; // Lazy load react-big-calendar (~60KB + date-fns) const BigCalendar = dynamic( () => import('@/components/calendar/big-calendar-wrapper').then((m) => m.BigCalendarWrapper), { ssr: false, loading: () => (
Loading calendar...
), } ); interface CalendarEvent { id: string; title: string; start: Date; end: Date; type: 'task' | 'habit' | 'project' | 'milestone'; domain: string; color: string; } export default function CalendarPage() { const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); const [showTasks, setShowTasks] = useState(true); const [showHabits, setShowHabits] = useState(true); const [showProjects, setShowProjects] = useState(true); const [showMilestones, setShowMilestones] = useState(true); const [selectedDomains, setSelectedDomains] = useState([]); useEffect(() => { fetchEvents(); }, []); async function fetchEvents() { try { // Fetch tasks with due dates const tasksResponse = await fetch('/api/tasks?filter=due_date!%3D%22%22&perPage=500'); const tasksData = tasksResponse.ok ? await tasksResponse.json() : { items: [] }; // Fetch projects with target dates const projectsResponse = await fetch('/api/projects?filter=target_date!%3D%22%22&perPage=500'); const projectsData = projectsResponse.ok ? await projectsResponse.json() : { items: [] }; // Fetch milestones with target dates const milestonesResponse = await fetch('/api/milestones?filter=target_date!%3D%22%22&perPage=500'); const milestonesData = milestonesResponse.ok ? await milestonesResponse.json() : { items: [] }; const calendarEvents: CalendarEvent[] = []; // Add tasks if (tasksData.items) { for (const task of tasksData.items) { if (task.due_date) { const date = new Date(task.due_date); calendarEvents.push({ id: `task-${task.id}`, title: task.title, start: date, end: date, type: 'task', domain: task.domain ?? 'personal', color: '#3b82f6', // blue }); } } } // Add projects if (projectsData.items) { for (const project of projectsData.items) { if (project.target_date) { const date = new Date(project.target_date); calendarEvents.push({ id: `project-${project.id}`, title: `📁 ${project.name}`, start: date, end: date, type: 'project', domain: project.domain ?? 'personal', color: '#8b5cf6', // purple }); } } } // Add milestones if (milestonesData.items) { for (const milestone of milestonesData.items) { if (milestone.target_date) { const date = new Date(milestone.target_date); calendarEvents.push({ id: `milestone-${milestone.id}`, title: `🎯 ${milestone.name}`, start: date, end: date, type: 'milestone', domain: milestone.domain ?? 'work', color: '#f59e0b', // amber }); } } } setEvents(calendarEvents); } catch (error) { console.error('Failed to fetch calendar events:', error); } finally { setLoading(false); } } const filteredEvents = useMemo(() => { return events.filter((event) => { // Filter by type if (event.type === 'task' && !showTasks) return false; if (event.type === 'habit' && !showHabits) return false; if (event.type === 'project' && !showProjects) return false; if (event.type === 'milestone' && !showMilestones) return false; // Filter by domain if (selectedDomains.length > 0 && !selectedDomains.includes(event.domain)) { return false; } return true; }); }, [events, showTasks, showHabits, showProjects, showMilestones, selectedDomains]); function toggleDomain(domain: string) { setSelectedDomains((prev) => prev.includes(domain) ? prev.filter((d) => d !== domain) : [...prev, domain] ); } if (loading) { return (

Loading calendar...

); } return (

Calendar

Your commitments, in time.

{/* Filters sidebar */} {/* Entity types */}

Show

setShowTasks(checked === true)} />
); }