import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { apiClient } from "../lib/apiClient"; import { Users, Search, Plus, ShieldAlert, Trash2, Mail, Building, Globe, MapPin, Linkedin, Phone, Filter, Clock, CheckCircle2, Ban, ArrowUpRight } from "lucide-react"; import { useState } from "react"; import StatusBadge from "../components/StatusBadge"; import FormDrawer from "../components/FormDrawer"; import CsvExportButton from "../components/CsvExportButton"; import ConfirmModal from "../components/ConfirmModal"; import toast from "react-hot-toast"; const STATUSES = [ "ALL", "INTERESTED", "MEETING_BOOKED", "MEETING_DONE", "REPLIED", "NOT_INTERESTED", "UNSUBSCRIBED", "BOUNCED", "DO_NOT_CONTACT" ]; export default function Leads() { const queryClient = useQueryClient(); const [activeTab, setActiveTab] = useState<"leads" | "blocklist">("leads"); const [searchQuery, setSearchQuery] = useState(""); const [selectedStatus, setSelectedStatus] = useState("ALL"); const [selectedLead, setSelectedLead] = useState(null); const [isAddLeadOpen, setIsAddLeadOpen] = useState(false); const [isAddBlocklistOpen, setIsAddBlocklistOpen] = useState(false); const [blocklistType, setBlocklistType] = useState<"email" | "domain">("email"); const { data: leads = [], isLoading } = useQuery({ queryKey: ["leads-search", searchQuery, selectedStatus], queryFn: async () => { const res = await apiClient.get("/leads/search", { params: { q: searchQuery, status: selectedStatus }, }); return res.data; }, }); const { data: emailBlockList = [], refetch: refetchEmailBlockList } = useQuery({ queryKey: ["blocklist-emails"], queryFn: async () => { const res = await apiClient.get("/leads/block-list"); return res.data; }, }); const { data: domainBlockList = [], refetch: refetchDomainBlockList } = useQuery({ queryKey: ["blocklist-domains"], queryFn: async () => { const res = await apiClient.get("/leads/domain-block-list"); return res.data; }, }); const updateLeadStatusMutation = useMutation({ mutationFn: async ({ campaignId, leadId, status }: { campaignId: string; leadId: string; status: string }) => { const res = await apiClient.post(`/campaigns/${campaignId}/leads/status`, { lead_id: leadId, status }); return res.data; }, onSuccess: () => { toast.success("Lead status updated"); queryClient.invalidateQueries({ queryKey: ["leads-search"] }); }, }); const deleteLeadMutation = useMutation({ mutationFn: async ({ campaignId, leadId }: { campaignId: string; leadId: string }) => { const res = await apiClient.delete(`/campaigns/${campaignId}/leads/${leadId}`); return res.data; }, onSuccess: () => { toast.success("Lead removed"); setSelectedLead(null); queryClient.invalidateQueries({ queryKey: ["leads-search"] }); }, }); return (
{/* Header */}

Lead Intelligence Database

Global repository of targeted prospects, responses, and suppression blocklists.

{/* Main Tabs */}
{activeTab === "leads" && (
{/* Filter Bar */}
setSearchQuery(e.target.value)} className="w-full bg-black/40 border border-white/5 rounded-lg py-2 pl-9 pr-4 text-xs text-zinc-100 placeholder:text-zinc-500 focus:outline-none focus:border-indigo-500 shadow-[inset_0_1px_1px_rgba(246,248,242,0.02)] transition-all" />
{/* Leads Table */}
{leads.map((lead: any) => ( setSelectedLead(lead)} className="hover:bg-white/5 transition-colors cursor-pointer" > ))} {leads.length === 0 && !isLoading && ( )}
Prospect Company Status Engagement Location Actions
{lead.first_name} {lead.last_name}
{lead.email}
{lead.company_name}
{lead.website && (
{lead.website.replace("https://", "")}
)}
{lead.open_count || 0} opens •{" "} {lead.click_count || 0} clicks
{lead.location || "United States"}
No prospect leads matching current filters.
)} {/* SUB-TAB: BLOCKLIST MANAGER */} {activeTab === "blocklist" && (
{/* Email Blocklist */}

Email Address Blocklist

Suppressed emails never receive outreach.

{emailBlockList.map((item: any) => (
{item.email}
{item.reason}
))}
{/* Domain Blocklist */}

Domain Suppression List

Blocks all emails under specified root domains.

{domainBlockList.map((item: any) => (
@{item.domain}
{item.reason}
))}
)} {/* Lead Detail Slide-Over Drawer */} setSelectedLead(null)} title="Prospect Dossier" subtitle={selectedLead ? `${selectedLead.first_name} ${selectedLead.last_name} (${selectedLead.email})` : ""} > {selectedLead && (
{/* Status Change Card */}
{/* Profile Fields */}

Contact Info

Company {selectedLead.company_name}
Location {selectedLead.location || "N/A"}
Phone {selectedLead.phone_number || "N/A"}
LinkedIn {selectedLead.linkedin_profile ? ( View LinkedIn Profile ) : ( Not provided )}
{/* Custom Fields */} {selectedLead.custom_fields && Object.keys(selectedLead.custom_fields).length > 0 && (

Custom Attributes

{Object.entries(selectedLead.custom_fields).map(([key, val]) => (
{key} {String(val)}
))}
)} {/* Timeline */}

Activity Timeline

Email Delivered & Opened
2 hours ago
Enrolled in Enterprise SaaS Sequence
3 days ago
{/* Delete Lead Button */}
)} {/* Add Lead Slide-Over */} setIsAddLeadOpen(false)} title="Add Global Prospect Lead" subtitle="Input contact info, company details, and custom variables for personalization." >
{ e.preventDefault(); const form = e.target as HTMLFormElement; const newLead = { first_name: (form.elements.namedItem("first_name") as HTMLInputElement).value, last_name: (form.elements.namedItem("last_name") as HTMLInputElement).value, email: (form.elements.namedItem("email") as HTMLInputElement).value, phone_number: (form.elements.namedItem("phone_number") as HTMLInputElement).value, company_name: (form.elements.namedItem("company_name") as HTMLInputElement).value, website: (form.elements.namedItem("website") as HTMLInputElement).value, location: (form.elements.namedItem("location") as HTMLInputElement).value, linkedin_profile: (form.elements.namedItem("linkedin_profile") as HTMLInputElement).value, status: "INTERESTED", }; try { await apiClient.post("/campaigns/camp_9901/leads", newLead); toast.success("Prospect added to database"); setIsAddLeadOpen(false); queryClient.invalidateQueries({ queryKey: ["leads-search"] }); } catch (err: any) { toast.error("Failed to add prospect"); } }} className="space-y-3.5 text-xs" >
{/* Add Blocklist Modal */} setIsAddBlocklistOpen(false)} title={blocklistType === "email" ? "Add Email to Suppression Blocklist" : "Add Domain to Suppression Blocklist"} subtitle="Blocked records will never receive any emails from any campaign." >
{ e.preventDefault(); const form = e.target as HTMLFormElement; const val = (form.elements.namedItem("val") as HTMLInputElement).value; const reason = (form.elements.namedItem("reason") as HTMLInputElement).value; try { if (blocklistType === "email") { await apiClient.post("/leads/block-list", { email: val, reason }); refetchEmailBlockList(); } else { await apiClient.post("/leads/domain-block-list", { domain: val, reason }); refetchDomainBlockList(); } toast.success("Suppression entry saved"); setIsAddBlocklistOpen(false); } catch (err: any) { toast.error("Failed to add entry"); } }} className="space-y-4 text-xs" >
); }