Fix upcoming widget showing past items (yesterday's events, overdue todos)

- Add lower-bound date filter (>= today) for todos and reminders in /upcoming endpoint
- Accept client_date param for timezone-correct filtering
- Pass client_date from frontend to /upcoming API call

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-02-21 11:54:52 +08:00
parent fa7b50233e
commit c2c4446ea6
2 changed files with 10 additions and 5 deletions

View File

@ -130,25 +130,27 @@ async def get_dashboard(
@router.get("/upcoming") @router.get("/upcoming")
async def get_upcoming( async def get_upcoming(
days: int = Query(default=7, ge=1, le=90), days: int = Query(default=7, ge=1, le=90),
client_date: Optional[date] = Query(None),
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
current_user: Settings = Depends(get_current_session) current_user: Settings = Depends(get_current_session)
): ):
"""Get unified list of upcoming items (todos, events, reminders) sorted by date.""" """Get unified list of upcoming items (todos, events, reminders) sorted by date."""
today = date.today() today = client_date or date.today()
cutoff_date = today + timedelta(days=days) cutoff_date = today + timedelta(days=days)
cutoff_datetime = datetime.combine(cutoff_date, datetime.max.time()) cutoff_datetime = datetime.combine(cutoff_date, datetime.max.time())
today_start = datetime.combine(today, datetime.min.time())
# Get upcoming todos with due dates # Get upcoming todos with due dates (today onward only)
todos_query = select(Todo).where( todos_query = select(Todo).where(
Todo.completed == False, Todo.completed == False,
Todo.due_date.isnot(None), Todo.due_date.isnot(None),
Todo.due_date >= today,
Todo.due_date <= cutoff_date Todo.due_date <= cutoff_date
) )
todos_result = await db.execute(todos_query) todos_result = await db.execute(todos_query)
todos = todos_result.scalars().all() todos = todos_result.scalars().all()
# Get upcoming events (from today onward) # Get upcoming events (from today onward)
today_start = datetime.combine(today, datetime.min.time())
events_query = select(CalendarEvent).where( events_query = select(CalendarEvent).where(
CalendarEvent.start_datetime >= today_start, CalendarEvent.start_datetime >= today_start,
CalendarEvent.start_datetime <= cutoff_datetime, CalendarEvent.start_datetime <= cutoff_datetime,
@ -156,10 +158,11 @@ async def get_upcoming(
events_result = await db.execute(events_query) events_result = await db.execute(events_query)
events = events_result.scalars().all() events = events_result.scalars().all()
# Get upcoming reminders # Get upcoming reminders (today onward only)
reminders_query = select(Reminder).where( reminders_query = select(Reminder).where(
Reminder.is_active == True, Reminder.is_active == True,
Reminder.is_dismissed == False, Reminder.is_dismissed == False,
Reminder.remind_at >= today_start,
Reminder.remind_at <= cutoff_datetime Reminder.remind_at <= cutoff_datetime
) )
reminders_result = await db.execute(reminders_query) reminders_result = await db.execute(reminders_query)

View File

@ -59,7 +59,9 @@ export default function DashboardPage() {
queryKey: ['upcoming', settings?.upcoming_days], queryKey: ['upcoming', settings?.upcoming_days],
queryFn: async () => { queryFn: async () => {
const days = settings?.upcoming_days || 7; const days = settings?.upcoming_days || 7;
const { data } = await api.get<UpcomingResponse>(`/upcoming?days=${days}`); 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<UpcomingResponse>(`/upcoming?days=${days}&client_date=${clientDate}`);
return data; return data;
}, },
}); });