Kanban Board: Search, Undo Toast & Priorities
hard⏱ 20 minreactlesson
Build three features on top of a working Kanban board. The baseline already ships: four columns rendered from a column registry, add-card targeting a dropdown-selected column, drag-and-drop across columns (and reordering within one), inline title/description editing, delete, and localStorage persistence.
The data model — two states joined by column id, with no duplicated task data. COLUMNS answers what columns exist, in what order, and what they're called; tasksByCol answers what's inside each column (its keys must match the keys of COLUMNS).
Your tasks:
- TODO(A) — Search / Filter: real-time and case-insensitive, matching title OR description. Non-destructive — never mutate
tasksByCol; derive the visible view with useMemo. Decide whether the count badges show filtered or total counts.
- TODO(B) — Delete toast with Undo: the toast lasts 5 seconds, then the delete becomes permanent. Undo restores the card to the same column at the same index. Only the latest delete is undoable.
- TODO(C) — Priority: a low/medium/high badge on each card; clicking it cycles the value; new cards default to medium.
Why this happens
The board has a single source of truth: tasksByCol owns card placement. The search result must be a derived view (useMemo over tasksByCol + query) — storing it as a third piece of state would desync the moment a card moves. Delete + Undo needs exactly one snapshot { task, columnId, index } and one timer id: a new delete overwrites both, which is precisely why "only the latest delete is undoable" falls out for free, with no extra bookkeeping. The timer id lives in a useRef because it isn't render state — changing it must not re-render. Priority is a pure cycle over ["low", "medium", "high"], defaulting to medium at creation.