diff --git a/backend/app/routers/dashboard.py b/backend/app/routers/dashboard.py index fb35872..7ef8220 100644 --- a/backend/app/routers/dashboard.py +++ b/backend/app/routers/dashboard.py @@ -14,6 +14,13 @@ from app.routers.auth import get_current_session router = APIRouter() +# Reusable filter: exclude parent template events (they have a real recurrence_rule). +# Some legacy events have "" instead of NULL, so allow both. +_not_parent_template = or_( + CalendarEvent.recurrence_rule == None, + CalendarEvent.recurrence_rule == "", +) + @router.get("/dashboard") async def get_dashboard( @@ -31,7 +38,7 @@ async def get_dashboard( events_query = select(CalendarEvent).where( CalendarEvent.start_datetime >= today_start, CalendarEvent.start_datetime <= today_end, - or_(CalendarEvent.recurrence_rule == None, CalendarEvent.recurrence_rule == ""), + _not_parent_template, ) events_result = await db.execute(events_query) todays_events = events_result.scalars().all() @@ -77,7 +84,7 @@ async def get_dashboard( starred_query = select(CalendarEvent).where( CalendarEvent.is_starred == True, CalendarEvent.start_datetime > now, - or_(CalendarEvent.recurrence_rule == None, CalendarEvent.recurrence_rule == ""), + _not_parent_template, ).order_by(CalendarEvent.start_datetime.asc()).limit(5) starred_result = await db.execute(starred_query) starred_events = starred_result.scalars().all() @@ -158,7 +165,7 @@ async def get_upcoming( events_query = select(CalendarEvent).where( CalendarEvent.start_datetime >= today_start, CalendarEvent.start_datetime <= cutoff_datetime, - or_(CalendarEvent.recurrence_rule == None, CalendarEvent.recurrence_rule == ""), + _not_parent_template, ) events_result = await db.execute(events_query) events = events_result.scalars().all() diff --git a/frontend/src/components/dashboard/DayBriefing.tsx b/frontend/src/components/dashboard/DayBriefing.tsx index 9bf0aa2..c1019d9 100644 --- a/frontend/src/components/dashboard/DayBriefing.tsx +++ b/frontend/src/components/dashboard/DayBriefing.tsx @@ -45,11 +45,13 @@ export default function DayBriefing({ upcomingItems, dashboardData, weatherData if (hour >= 21 || hour < 5) { // Before 5 AM, "today" still matters — mention remaining items if (todayItems.length > 0 && hour < 5) { - const remainingToday = todayEvents.filter((e) => isAfter(new Date(e.end_datetime), now)); + const remainingToday = todayEvents.filter((e) => e.end_datetime && isAfter(new Date(e.end_datetime), now)); if (remainingToday.length > 0) { parts.push(`${remainingToday.length} event${remainingToday.length > 1 ? 's' : ''} still on today.`); } else if (todayTodos.length > 0) { parts.push(`${todayTodos.length} task${todayTodos.length > 1 ? 's' : ''} due today.`); + } else if (activeReminders.length > 0) { + parts.push(`${activeReminders.length} reminder${activeReminders.length > 1 ? 's' : ''} set for today.`); } } @@ -92,7 +94,7 @@ export default function DayBriefing({ upcomingItems, dashboardData, weatherData } // Afternoon (12PM–5PM) else if (hour < 17) { - const remainingEvents = todayEvents.filter((e) => isAfter(new Date(e.end_datetime), now)); + const remainingEvents = todayEvents.filter((e) => e.end_datetime && isAfter(new Date(e.end_datetime), now)); const completedTodos = todayTodos.length === 0; if (remainingEvents.length === 0 && completedTodos) { parts.push('The rest of your afternoon is clear.'); @@ -109,7 +111,7 @@ export default function DayBriefing({ upcomingItems, dashboardData, weatherData } // Evening (5PM–9PM) else { - const eveningEvents = todayEvents.filter((e) => isAfter(new Date(e.end_datetime), now)); + const eveningEvents = todayEvents.filter((e) => e.end_datetime && isAfter(new Date(e.end_datetime), now)); if (eveningEvents.length === 0 && tomorrowItems.length === 0) { parts.push('Nothing left tonight, and tomorrow is clear too.'); } else {