From 683a1b553e9d16dd3d40d7e7e1965be1ead81ae4 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:57:15 +0000 Subject: [PATCH 1/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/contacts.index.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index 4d342b0..ef908dd 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -14,6 +14,21 @@ import { Plus, Search, Mail, Phone, Building2, ChevronRight, Edit, Trash2, Brief import { ContactFormDialog, CONTACT_TYPES, type ContactRecord } from "@/components/contacts/contact-form-dialog"; import { setArchived } from "@/lib/archive"; +type Category = "all" | "companies" | "people" | "lawyers"; + +const CATEGORY_TYPES: Record, string[]> = { + lawyers: ["opposing_counsel", "co_counsel"], + companies: ["vendor", "court"], + people: ["expert", "witness", "process_server", "client_contact", "other"], +}; + +function categoryOf(type: string | null | undefined): Exclude { + const t = type ?? "other"; + if (CATEGORY_TYPES.lawyers.includes(t)) return "lawyers"; + if (CATEGORY_TYPES.companies.includes(t)) return "companies"; + return "people"; +} + export const Route = createFileRoute("/contacts/")({ component: () => ( From 6db4ab214fbc40a9551173538aeaf76e045e7fa8 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:57:21 +0000 Subject: [PATCH 2/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/contacts.index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index ef908dd..0ff1903 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -52,6 +52,7 @@ function ContactsIndex() { const [q, setQ] = useState(""); const [typeFilter, setTypeFilter] = useState("all"); const [view, setView] = useState<"active" | "archived">("active"); + const [category, setCategory] = useState("all"); const [editing, setEditing] = useState(null); const [open, setOpen] = useState(false); From cc079c1716e59266a786e8e7f2eec8dfba5aeebb Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:57:38 +0000 Subject: [PATCH 3/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/contacts.index.tsx | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index 0ff1903..a41c055 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -86,6 +86,7 @@ function ContactsIndex() { const term = q.trim().toLowerCase(); return rows.filter((r) => { if (view === "archived" ? !r.archived_at : !!r.archived_at) return false; + if (category !== "all" && categoryOf(r.contact_type) !== category) return false; if (typeFilter !== "all" && r.contact_type !== typeFilter) return false; if (!term) return true; return ( @@ -95,11 +96,36 @@ function ContactsIndex() { (r.phone ?? "").toLowerCase().includes(term) ); }); - }, [rows, q, typeFilter, view]); + }, [rows, q, typeFilter, view, category]); + + 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); + } + return Array.from(map.entries()).sort(([a], [b]) => { + if (a === "#") return 1; + if (b === "#") return -1; + return a.localeCompare(b); + }); + }, [filtered]); const archivedCount = rows.filter((r) => r.archived_at).length; const activeCount = rows.length - archivedCount; + const categoryCounts = useMemo(() => { + const base = rows.filter((r) => (view === "archived" ? !!r.archived_at : !r.archived_at)); + return { + all: base.length, + companies: base.filter((r) => categoryOf(r.contact_type) === "companies").length, + people: base.filter((r) => categoryOf(r.contact_type) === "people").length, + lawyers: base.filter((r) => categoryOf(r.contact_type) === "lawyers").length, + }; + }, [rows, view]); + const remove = async (id: string, name: string) => { if (!confirm(`Delete contact "${name}"? This will also remove all case and client links.`)) return; const { error } = await supabase.from("contacts").delete().eq("id", id); From 231a842620db05e500c72c6e6a02b476aca70d21 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:57:55 +0000 Subject: [PATCH 4/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/contacts.index.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index a41c055..11618fa 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -192,6 +192,15 @@ function ContactsIndex() { + setCategory(v as Category)} className="mb-4"> + + All ({categoryCounts.all}) + Companies ({categoryCounts.companies}) + People ({categoryCounts.people}) + Lawyers ({categoryCounts.lawyers}) + + + {loading ? ( @@ -201,8 +210,14 @@ function ContactsIndex() { {rows.length === 0 ? "No contacts yet." : view === "archived" ? "No archived contacts." : "No contacts match your filters."}

) : ( -
    - {filtered.map((c) => { +
    + {grouped.map(([letter, items]) => ( +
    +
    + {letter} +
    +
      + {items.map((c) => { const typeLabel = CONTACT_TYPES.find((t) => t.value === c.contact_type)?.label ?? c.contact_type; const canEdit = isAdmin || c.created_by === user?.id; return ( From 3683800be0264acc66240de7c66042f0acd13f2c Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:58:05 +0000 Subject: [PATCH 5/5] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/routes/contacts.index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/contacts.index.tsx b/src/routes/contacts.index.tsx index 11618fa..67c830f 100644 --- a/src/routes/contacts.index.tsx +++ b/src/routes/contacts.index.tsx @@ -270,7 +270,10 @@ function ContactsIndex() { ); })} -
    +
+ + ))} + )}