import { FormEvent, useEffect, useMemo, useState } from 'react'; import { createCategory, createTodo, deleteCategory, deleteTodo, getCategories, getTodos, updateCategory, updateTodo, } from './api'; import type { Category, Todo } from './types'; const DEFAULT_COLOR = '#6366f1'; const COLORS = [DEFAULT_COLOR, '#0ea5e9', '#f97316', '#10b981', '#ec4899']; export function App() { const [categories, setCategories] = useState([]); const [todos, setTodos] = useState([]); const [selectedCategoryId, setSelectedCategoryId] = useState(null); const [draft, setDraft] = useState(''); const [draftCategoryId, setDraftCategoryId] = useState(null); const [categoryName, setCategoryName] = useState(''); const [categoryColor, setCategoryColor] = useState(DEFAULT_COLOR); const [editingCategoryId, setEditingCategoryId] = useState(null); const [error, setError] = useState(null); const selectedCategory = useMemo( () => categories.find(category => category.id === selectedCategoryId) ?? null, [categories, selectedCategoryId], ); const totalCount = useMemo( () => categories.reduce((total, category) => total + category.todo_count, 0), [categories], ); async function load() { const [nextCategories, nextTodos] = await Promise.all([ getCategories(), getTodos(selectedCategoryId), ]); setCategories(nextCategories); setTodos(nextTodos); } useEffect(() => { load().catch(handleError); }, [selectedCategoryId]); function handleError(err: unknown) { setError(err instanceof Error ? err.message : String(err)); } async function onSubmit(event: FormEvent) { event.preventDefault(); const title = draft.trim(); if (!title) return; try { await createTodo(title, selectedCategoryId ?? draftCategoryId); setDraft(''); await load(); } catch (err) { handleError(err); } } async function onCategorySubmit(event: FormEvent) { event.preventDefault(); const name = categoryName.trim(); if (!name) return; try { if (editingCategoryId !== null) { await updateCategory(editingCategoryId, { name, color: categoryColor }); } else { await createCategory(name, categoryColor); } setCategoryName(''); setCategoryColor(DEFAULT_COLOR); setEditingCategoryId(null); await load(); } catch (err) { handleError(err); } } function startEditCategory(category: Category) { setEditingCategoryId(category.id); setCategoryName(category.name); setCategoryColor(category.color); } async function removeCategory(categoryId: number) { try { await deleteCategory(categoryId); if (selectedCategoryId === categoryId) setSelectedCategoryId(null); await load(); } catch (err) { handleError(err); } } return (

{selectedCategory?.name ?? 'All categories'}

{selectedCategory ? `${selectedCategory.name} tasks` : 'Today\'s tasks'}

setDraft(event.target.value)} placeholder="Add a task..." /> {!selectedCategoryId ? ( ) : null}
{error ?

{error}

: null}
{todos.map(todo => (
{todo.category_name ? ( {todo.category_name} ) : null}
))} {todos.length === 0 ?

No tasks yet. Add one above.

: null}
); }