From c36802864c07c9334ccd48d3e398312fc64c9d81 Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Tue, 31 Mar 2026 13:18:31 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20Lead=20Master=20=E2=80=94=20campaign=20?= =?UTF-8?q?filter=20pills=20+=20fixed-height=20table=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Campaign filter pills: clickable badges for each campaign + "No Campaign", toggle filtering - Fixed-height layout: header/tabs/pills pinned, table fills viewport with internal scroll, pagination pinned at bottom Co-Authored-By: Claude Opus 4.6 (1M context) --- src/pages/all-leads.tsx | 80 ++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/src/pages/all-leads.tsx b/src/pages/all-leads.tsx index 664d1aa..eae6eb3 100644 --- a/src/pages/all-leads.tsx +++ b/src/pages/all-leads.tsx @@ -24,6 +24,7 @@ import { LeadActivitySlideout } from '@/components/leads/lead-activity-slideout' import { useLeads } from '@/hooks/use-leads'; import { useAuth } from '@/providers/auth-provider'; import { useData } from '@/providers/data-provider'; +import { cx } from '@/utils/cx'; import type { Lead, LeadSource, LeadStatus } from '@/types/entities'; type TabKey = 'new' | 'my-leads' | 'all'; @@ -57,7 +58,8 @@ export const AllLeadsPage = () => { search: searchQuery || undefined, }); - const { agents, templates, leadActivities } = useData(); + const { agents, templates, leadActivities, campaigns } = useData(); + const [campaignFilter, setCampaignFilter] = useState(null); // Client-side sorting const sortedLeads = useMemo(() => { @@ -114,13 +116,19 @@ export const AllLeadsPage = () => { return sorted; }, [filteredLeads, sortField, sortDirection]); - // Apply "My Leads" filter when on that tab + // Apply "My Leads" + campaign filter const displayLeads = useMemo(() => { + let result = sortedLeads; if (myLeadsOnly) { - return sortedLeads.filter((l) => l.assignedAgent === user.name); + result = result.filter((l) => l.assignedAgent === user.name); } - return sortedLeads; - }, [sortedLeads, myLeadsOnly, user.name]); + if (campaignFilter) { + result = campaignFilter === '__none__' + ? result.filter((l) => !l.campaignId) + : result.filter((l) => l.campaignId === campaignFilter); + } + return result; + }, [sortedLeads, myLeadsOnly, user.name, campaignFilter]); // Client-side pagination const totalPages = Math.max(1, Math.ceil(displayLeads.length / PAGE_SIZE)); @@ -203,9 +211,9 @@ export const AllLeadsPage = () => {
-
+
{/* Tabs + Controls row */} -
+
+ {campaigns.map(c => { + const isActive = campaignFilter === c.id; + const count = filteredLeads.filter(l => l.campaignId === c.id).length; + return ( + + ); + })} + +
+ )} + {/* Bulk action bar */} {selectedIds.length > 0 && ( -
+
{
)} - {/* Table */} -
+ {/* Table — fills remaining space, scrolls internally */} +
{ />
- {/* Pagination */} + {/* Pagination — pinned at bottom */} {totalPages > 1 && ( -
+