import { useState, useEffect, useRef } from 'react'; import { useQuery } from '@tanstack/react-query'; import { format } from 'date-fns'; import { Bell, Plus, Calendar as CalIcon, ListTodo } from 'lucide-react'; import api from '@/lib/api'; import type { DashboardData, UpcomingResponse, WeatherData } from '@/types'; import { useSettings } from '@/hooks/useSettings'; import { useAlerts } from '@/hooks/useAlerts'; import StatsWidget from './StatsWidget'; import TodoWidget from './TodoWidget'; import CalendarWidget from './CalendarWidget'; import UpcomingWidget from './UpcomingWidget'; import WeekTimeline from './WeekTimeline'; import DayBriefing from './DayBriefing'; import CountdownWidget from './CountdownWidget'; import TrackedProjectsWidget from './TrackedProjectsWidget'; import AlertBanner from './AlertBanner'; import EventForm from '../calendar/EventForm'; import TodoForm from '../todos/TodoForm'; import ReminderForm from '../reminders/ReminderForm'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { DashboardSkeleton } from '@/components/ui/skeleton'; function getGreeting(name?: string): string { const hour = new Date().getHours(); const suffix = name ? `, ${name}.` : '.'; if (hour < 5) return `Good night${suffix}`; if (hour < 12) return `Good morning${suffix}`; if (hour < 17) return `Good afternoon${suffix}`; if (hour < 21) return `Good evening${suffix}`; return `Good night${suffix}`; } export default function DashboardPage() { const { settings } = useSettings(); const { alerts, dismiss: dismissAlert, snooze: snoozeAlert } = useAlerts(); const [quickAddType, setQuickAddType] = useState<'event' | 'todo' | 'reminder' | null>(null); const [dropdownOpen, setDropdownOpen] = useState(false); const dropdownRef = useRef(null); useEffect(() => { function handleClickOutside(e: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) { setDropdownOpen(false); } } if (dropdownOpen) document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [dropdownOpen]); const { data, isLoading } = useQuery({ queryKey: ['dashboard'], queryFn: async () => { const now = new Date(); const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`; const { data } = await api.get(`/dashboard?client_date=${today}`); return data; }, }); const { data: upcomingData } = useQuery({ queryKey: ['upcoming', settings?.upcoming_days], queryFn: async () => { const days = settings?.upcoming_days || 7; const now = new Date(); const clientDate = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`; const { data } = await api.get(`/upcoming?days=${days}&client_date=${clientDate}`); return data; }, }); const { data: weatherData } = useQuery({ queryKey: ['weather'], queryFn: async () => { const { data } = await api.get('/weather'); return data; }, staleTime: 30 * 60 * 1000, retry: false, enabled: !!(settings?.weather_city || (settings?.weather_lat != null && settings?.weather_lon != null)), }); if (isLoading) { return (
); } if (!data) { return (
Failed to load dashboard
); } return (
{/* Header — greeting + date + quick add */}

{getGreeting(settings?.preferred_name || undefined)}

{format(new Date(), 'EEEE, MMMM d, yyyy')}

{dropdownOpen && (
)}
{/* Week Timeline */} {upcomingData && (
)} {/* Smart Briefing */} {upcomingData && ( )} {/* Stats Row */}
{/* Alert Banner */} {/* Main Content — 2 columns */}
{/* Left: Upcoming feed (wider) */}
{upcomingData && upcomingData.items.length > 0 ? ( ) : ( Upcoming

Nothing upcoming. Enjoy the quiet.

)}
{/* Right: Countdown + Today's events + todos stacked */}
{data.starred_events.length > 0 && ( )}
{/* Active Reminders — exclude those already shown in alert banner */} {(() => { const alertIds = new Set(alerts.map((a) => a.id)); const futureReminders = data.active_reminders.filter((r) => !alertIds.has(r.id)); if (futureReminders.length === 0) return null; return (
Active Reminders
{futureReminders.map((reminder) => (
{reminder.title} {reminder.remind_at ? format(new Date(reminder.remind_at), 'MMM d, h:mm a') : ''}
))}
); })()} {/* Tracked Projects */}
{/* Quick Add Forms */} {quickAddType === 'event' && setQuickAddType(null)} />} {quickAddType === 'todo' && setQuickAddType(null)} />} {quickAddType === 'reminder' && setQuickAddType(null)} />}
); }