"use client"; import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { UserPlus, RefreshCw } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card"; import { Table, TableHead, TableBody, TableRow, Th, Td, EmptyState } from "@/components/ui/Table"; import { Badge } from "@/components/ui/Badge"; import { Button } from "@/components/ui/Button"; import { Input } from "@/components/ui/Input"; import { Modal } from "@/components/ui/Modal"; import { formatDate } from "@/lib/utils"; import api from "@/lib/api"; import { toast } from "sonner"; import type { Lead } from "@/types"; const statusVariant: Record = { NEW: "muted", CONTACTED: "default" as any, INTERESTED: "warning", CONVERTED: "success", LOST: "danger", }; const statusOptions = ["NEW", "CONTACTED", "INTERESTED", "CONVERTED", "LOST"]; export default function LeadsPage() { const qc = useQueryClient(); const [search, setSearch] = useState(""); const [selected, setSelected] = useState(null); const [showAdd, setShowAdd] = useState(false); const [form, setForm] = useState({ firstName: "", lastName: "", phone: "", email: "", address: "", notes: "", source: "" }); const [statusUpdate, setStatusUpdate] = useState(""); const { data = [], isLoading, refetch } = useQuery({ queryKey: ["leads", search], queryFn: async () => { const params = new URLSearchParams({ limit: "100" }); if (search) params.set("search", search); const res = await api.get(`/api/v1/leads?${params}`); const d = res.data; return Array.isArray(d) ? d : d.data ?? []; }, }); const addLead = useMutation({ mutationFn: async () => { await api.post("/api/v1/leads", { firstName: form.firstName, lastName: form.lastName, phone: form.phone, email: form.email || undefined, address: form.address || undefined, notes: form.notes || undefined, source: form.source || undefined, }); }, onSuccess: () => { toast.success("Lead added!"); setShowAdd(false); setForm({ firstName: "", lastName: "", phone: "", email: "", address: "", notes: "", source: "" }); qc.invalidateQueries({ queryKey: ["leads"] }); }, onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to add lead"), }); const updateStatus = useMutation({ mutationFn: async ({ id, status }: { id: string; status: string }) => { await api.patch(`/api/v1/leads/${id}`, { status }); }, onSuccess: () => { toast.success("Status updated!"); qc.invalidateQueries({ queryKey: ["leads"] }); if (selected) setSelected(prev => prev ? { ...prev, status: statusUpdate as Lead["status"] } : prev); }, onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to update"), }); const deleteLead = useMutation({ mutationFn: async (id: string) => { await api.delete(`/api/v1/leads/${id}`); }, onSuccess: () => { toast.success("Lead deleted"); setSelected(null); qc.invalidateQueries({ queryKey: ["leads"] }); }, onError: (e: any) => toast.error(e.response?.data?.message ?? "Failed to delete"), }); const counts = statusOptions.reduce((acc, s) => ({ ...acc, [s]: data.filter(l => l.status === s).length }), {} as Record); return (

Leads

Prospective customers pipeline

{/* Pipeline summary */}
{statusOptions.map(status => (

{counts[status] ?? 0}

{status}
))}

{data.length}

TOTAL

All Leads ({data.length}) setSearch(e.target.value)} />
{isLoading ? ( Array.from({ length: 6 }).map((_, i) => ( )) ) : data.length === 0 ? ( } /> ) : data.map(lead => ( { setSelected(lead); setStatusUpdate(lead.status); }} className="cursor-pointer hover:bg-blue-50 transition-colors"> ))}
NamePhoneEmailAddressStatusSourceAdded
{lead.firstName} {lead.lastName} {lead.phone} {lead.email ?? "—"} {lead.address ?? "—"} {lead.status} {lead.source ?? "—"} {formatDate(lead.createdAt)}
{/* Lead Detail Modal */} setSelected(null)} title={`${selected?.firstName ?? ""} ${selected?.lastName ?? ""}`}> {selected && (
Phone{selected.phone}
{selected.email &&
Email{selected.email}
} {selected.address &&
Address{selected.address}
} {selected.source &&
Source{selected.source}
} {selected.notes &&
Notes{selected.notes}
}
Added{formatDate(selected.createdAt)}
{statusOptions.map(s => ( ))}
{statusUpdate !== selected.status && ( )}
)}
{/* Add Lead Modal */} setShowAdd(false)} title="Add New Lead">
setForm(f => ({ ...f, firstName: e.target.value }))} /> setForm(f => ({ ...f, lastName: e.target.value }))} />
setForm(f => ({ ...f, phone: e.target.value }))} /> setForm(f => ({ ...f, email: e.target.value }))} /> setForm(f => ({ ...f, address: e.target.value }))} /> setForm(f => ({ ...f, source: e.target.value }))} />