diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index 1ff6b45..98bdce3 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -71,7 +71,12 @@ function ContactsIndex() { load(); }, []); - const filtered = useMemo(() => { + const letterOf = (name: string | null | undefined) => { + const ch = (name?.[0] ?? "#").toUpperCase(); + return /[A-Z]/.test(ch) ? ch : "#"; + }; + + const preLetterFiltered = useMemo(() => { const term = q.trim().toLowerCase(); return rows.filter((r) => { if (view === "archived" ? !r.archived_at : !!r.archived_at) return false; @@ -86,13 +91,26 @@ function ContactsIndex() { }); }, [rows, q, typeFilter, view]); + const letterCounts = useMemo(() => { + const counts: Record = { all: preLetterFiltered.length }; + for (const r of preLetterFiltered) { + const l = letterOf(r.name); + counts[l] = (counts[l] ?? 0) + 1; + } + return counts; + }, [preLetterFiltered]); + + const filtered = useMemo(() => { + if (letter === "all") return preLetterFiltered; + return preLetterFiltered.filter((r) => letterOf(r.name) === letter); + }, [preLetterFiltered, letter]); + const grouped = useMemo(() => { const map = new Map(); for (const r of filtered) { - const ch = (r.name?.[0] ?? "#").toUpperCase(); - const letter = /[A-Z]/.test(ch) ? ch : "#"; - if (!map.has(letter)) map.set(letter, []); - map.get(letter)!.push(r); + const l = letterOf(r.name); + if (!map.has(l)) map.set(l, []); + map.get(l)!.push(r); } return Array.from(map.entries()).sort(([a], [b]) => { if (a === "#") return 1;