From 607c2578f0a45af76a4ee27311308c12954ca327 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Fri, 19 Jun 2026 17:48:31 +0200 Subject: [PATCH] feat(19-01): add LeadsViewToggle with integrated search + list/kanban pill toggle - LeadsViewToggle: client wrapper with useState, useMemo filtered - Search input (left) + pill toggle Lista/Kanban (right) on single row - Filters leads by name/email/company/status/tags across both views - Search state preserved when switching between Lista and Kanban - LeadsSearch.tsx: replaced with re-export of LeadsViewToggle (backward compat) --- src/app/admin/leads/LeadsSearch.tsx | 49 +----------- .../admin/leads/LeadsViewToggle.tsx | 77 +++++++++++++++++++ 2 files changed, 80 insertions(+), 46 deletions(-) create mode 100644 src/components/admin/leads/LeadsViewToggle.tsx diff --git a/src/app/admin/leads/LeadsSearch.tsx b/src/app/admin/leads/LeadsSearch.tsx index 912c478..58505f1 100644 --- a/src/app/admin/leads/LeadsSearch.tsx +++ b/src/app/admin/leads/LeadsSearch.tsx @@ -1,46 +1,3 @@ -"use client"; - -import { useState, useMemo } from "react"; -import { Input } from "@/components/ui/input"; -import { Search } from "lucide-react"; -import { LeadTable } from "@/components/admin/leads/LeadTable"; -import type { LeadWithTags, LeadFieldOptions } from "@/lib/admin-queries"; - -export function LeadsSearch({ - leads, - options, -}: { - leads: LeadWithTags[]; - options: LeadFieldOptions; -}) { - const [query, setQuery] = useState(""); - - const filtered = useMemo(() => { - const q = query.trim().toLowerCase(); - if (!q) return leads; - return leads.filter((l) => { - if (l.name.toLowerCase().includes(q)) return true; - if (l.email?.toLowerCase().includes(q)) return true; - if (l.company?.toLowerCase().includes(q)) return true; - if (l.status.toLowerCase().includes(q)) return true; - if (l.tags.some((t) => t.toLowerCase().includes(q))) return true; - return false; - }); - }, [leads, query]); - - return ( -
-
- - setQuery(e.target.value)} - className="pl-9 h-9" - /> -
- -
- ); -} +// LeadsSearch is superseded by LeadsViewToggle (Phase 19). +// Re-exported here to avoid breaking any existing import. +export { LeadsViewToggle as LeadsSearch } from "@/components/admin/leads/LeadsViewToggle"; diff --git a/src/components/admin/leads/LeadsViewToggle.tsx b/src/components/admin/leads/LeadsViewToggle.tsx new file mode 100644 index 0000000..e5ccb30 --- /dev/null +++ b/src/components/admin/leads/LeadsViewToggle.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { useState, useMemo } from "react"; +import { Input } from "@/components/ui/input"; +import { Search } from "lucide-react"; +import { LeadTable } from "@/components/admin/leads/LeadTable"; +import { LeadsKanbanBoard } from "@/components/admin/leads/LeadsKanbanBoard"; +import type { LeadWithTags, LeadFieldOptions } from "@/lib/admin-queries"; + +export function LeadsViewToggle({ + leads, + options, +}: { + leads: LeadWithTags[]; + options: LeadFieldOptions; +}) { + const [view, setView] = useState<"list" | "kanban">("list"); + const [query, setQuery] = useState(""); + + const filtered = useMemo(() => { + const q = query.trim().toLowerCase(); + if (!q) return leads; + return leads.filter((l) => { + if (l.name.toLowerCase().includes(q)) return true; + if (l.email?.toLowerCase().includes(q)) return true; + if (l.company?.toLowerCase().includes(q)) return true; + if (l.status.toLowerCase().includes(q)) return true; + if (l.tags.some((t) => t.toLowerCase().includes(q))) return true; + return false; + }); + }, [leads, query]); + + return ( +
+
+
+ + setQuery(e.target.value)} + className="pl-9 h-9" + /> +
+
+ + +
+
+ + {view === "list" ? ( + + ) : ( + + )} +
+ ); +}