import { useState, useMemo, useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { Plus, Bell, BellOff, AlertCircle, Search } from 'lucide-react'; import { useQuery } from '@tanstack/react-query'; import { isPast, isToday, parseISO } from 'date-fns'; import api from '@/lib/api'; import type { Reminder } from '@/types'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent } from '@/components/ui/card'; import { ListSkeleton } from '@/components/ui/skeleton'; import ReminderList from './ReminderList'; import ReminderDetailPanel from './ReminderDetailPanel'; const statusFilters = [ { value: 'active', label: 'Active' }, { value: 'dismissed', label: 'Dismissed' }, { value: 'all', label: 'All' }, ] as const; type StatusFilter = (typeof statusFilters)[number]['value']; export default function RemindersPage() { const location = useLocation(); // Panel state const [selectedReminderId, setSelectedReminderId] = useState(null); const [panelMode, setPanelMode] = useState<'closed' | 'view' | 'create'>('closed'); const [filter, setFilter] = useState('active'); const [search, setSearch] = useState(''); // Handle navigation state from dashboard useEffect(() => { const state = location.state as { reminderId?: number } | null; if (state?.reminderId) { setSelectedReminderId(state.reminderId); setPanelMode('view'); window.history.replaceState({}, ''); } }, [location.state]); const { data: reminders = [], isLoading } = useQuery({ queryKey: ['reminders'], queryFn: async () => { const { data } = await api.get('/reminders'); return data; }, }); const filteredReminders = useMemo( () => reminders.filter((r) => { if (filter === 'active' && r.is_dismissed) return false; if (filter === 'dismissed' && !r.is_dismissed) return false; if (search && !r.title.toLowerCase().includes(search.toLowerCase())) return false; return true; }), [reminders, filter, search] ); const activeCount = reminders.filter((r) => !r.is_dismissed).length; const overdueCount = reminders.filter( (r) => !r.is_dismissed && r.remind_at && isPast(parseISO(r.remind_at)) && !isToday(parseISO(r.remind_at)) ).length; const dismissedCount = reminders.filter((r) => r.is_dismissed).length; const panelOpen = panelMode !== 'closed'; const selectedReminder = useMemo( () => reminders.find((r) => r.id === selectedReminderId) ?? null, [selectedReminderId, reminders], ); const handleSelect = (reminder: Reminder) => { setSelectedReminderId(reminder.id); setPanelMode('view'); }; const handleCreateNew = () => { setSelectedReminderId(null); setPanelMode('create'); }; const handlePanelClose = () => { setPanelMode('closed'); setSelectedReminderId(null); }; // Escape key closes panel useEffect(() => { if (!panelOpen) return; const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') handlePanelClose(); }; document.addEventListener('keydown', handler); return () => document.removeEventListener('keydown', handler); }, [panelOpen]); return (
{/* Header */}

Reminders

{statusFilters.map((sf) => ( ))}
setSearch(e.target.value)} className="w-52 h-8 pl-8 text-sm ring-inset" />
{/* Main content — list + detail panel */}
{/* Summary stats */} {!isLoading && reminders.length > 0 && (

Active

{activeCount}

Overdue

{overdueCount}

Dismissed

{dismissedCount}

)} {isLoading ? ( ) : ( )}
{/* Detail panel (desktop) */}
{/* Mobile detail panel overlay */} {panelOpen && (
e.stopPropagation()} >
)}
); }