import { useState, useMemo, useEffect } from 'react'; import { useMediaQuery, DESKTOP } from '@/hooks/useMediaQuery'; import { useLocation } from 'react-router-dom'; import { Plus, CheckSquare, CheckCircle2, AlertCircle } from 'lucide-react'; import { useQuery } from '@tanstack/react-query'; import api from '@/lib/api'; import type { Todo } from '@/types'; import { isTodoOverdue } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Select } from '@/components/ui/select'; import { Card, CardContent } from '@/components/ui/card'; import { ListSkeleton } from '@/components/ui/skeleton'; import { CategoryFilterBar } from '@/components/shared'; import MobileDetailOverlay from '@/components/shared/MobileDetailOverlay'; import { useCategoryOrder } from '@/hooks/useCategoryOrder'; import TodoList from './TodoList'; import TodoDetailPanel from './TodoDetailPanel'; const priorityFilters = [ { value: '', label: 'All' }, { value: 'none', label: 'None' }, { value: 'low', label: 'Low' }, { value: 'medium', label: 'Medium' }, { value: 'high', label: 'High' }, ] as const; export default function TodosPage() { const location = useLocation(); const isDesktop = useMediaQuery(DESKTOP); // Panel state const [selectedTodoId, setSelectedTodoId] = useState(null); const [panelMode, setPanelMode] = useState<'closed' | 'view' | 'create'>('closed'); // Filters const [priorityFilter, setPriorityFilter] = useState(''); const [activeFilters, setActiveFilters] = useState([]); const [showCompleted, setShowCompleted] = useState(true); const [search, setSearch] = useState(''); // Handle navigation state from dashboard useEffect(() => { const state = location.state as { todoId?: number } | null; if (state?.todoId) { setSelectedTodoId(state.todoId); setPanelMode('view'); window.history.replaceState({}, ''); } }, [location.state]); const { data: todos = [], isLoading } = useQuery({ queryKey: ['todos'], queryFn: async () => { const { data } = await api.get('/todos'); return data; }, }); const allCategories = useMemo(() => { const cats = new Set(); todos.forEach((t) => { if (t.category) cats.add(t.category); }); return Array.from(cats).sort(); }, [todos]); const { orderedCategories, reorder: reorderCategories } = useCategoryOrder('todos', allCategories); const filteredTodos = useMemo( () => todos.filter((todo) => { if (priorityFilter && todo.priority !== priorityFilter) return false; if (activeFilters.length > 0) { if (!todo.category || !activeFilters.includes(todo.category)) return false; } if (!showCompleted && todo.completed) return false; if (search && !todo.title.toLowerCase().includes(search.toLowerCase())) return false; return true; }), [todos, priorityFilter, activeFilters, showCompleted, search] ); const totalCount = filteredTodos.filter((t) => !t.completed).length; const completedCount = filteredTodos.filter((t) => t.completed).length; const overdueCount = filteredTodos.filter((t) => isTodoOverdue(t.due_date, t.completed)).length; const panelOpen = panelMode !== 'closed'; const selectedTodo = useMemo( () => todos.find((t) => t.id === selectedTodoId) ?? null, [selectedTodoId, todos], ); const handleSelect = (todo: Todo) => { setSelectedTodoId(todo.id); setPanelMode('view'); }; const handleCreateNew = () => { setSelectedTodoId(null); setPanelMode('create'); }; const handlePanelClose = () => { setPanelMode('closed'); setSelectedTodoId(null); }; // CategoryFilterBar handlers const toggleAll = () => setActiveFilters([]); const toggleCompleted = () => setShowCompleted((p) => !p); const toggleCategory = (cat: string) => { setActiveFilters((prev) => prev.includes(cat) ? prev.filter((c) => c !== cat) : [...prev, cat] ); }; const selectAllCategories = () => { const allSelected = orderedCategories.every((c) => activeFilters.includes(c)); setActiveFilters(allSelected ? [] : [...orderedCategories]); }; // 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 */}

Todos

{/* Priority filter */}
{priorityFilters.map((pf) => ( ))}
{/* Category filter bar (All + Completed + Categories with drag) */}
{/* Main content — list + detail panel */}
{/* Summary stats */} {!isLoading && todos.length > 0 && (

Open

{totalCount}

Completed

{completedCount}

Overdue

{overdueCount}

)} {isLoading ? ( ) : ( )}
{/* Detail panel (desktop) */} {panelOpen && isDesktop && (
)}
{/* Mobile detail panel overlay */} {panelOpen && !isDesktop && ( )}
); }