"use client"; import { useState, useEffect } from "react"; import { Plus, Send } from "lucide-react"; import { Button } from "@/components/ui/button"; import type { InvoiceListFilter, InvoiceRow } from "@/lib/supabase/invoicing-actions"; import { centsToDecimal, INVOICE_STATUS_LABELS } from "@/lib/supabase/invoicing-types"; import SendInvoiceModal from "@/components/invoices/SendInvoiceModal"; import { InvoiceChaseDialog } from "@/components/ai/InvoiceChaseDialog"; const FILTERS: { key: InvoiceListFilter; label: string }[] = [ { key: "all", label: "All" }, { key: "unpaid", label: "Unpaid" }, { key: "paid", label: "Paid" }, { key: "overdue", label: "Overdue" }, ]; function StatusBadge({ status }: { status: InvoiceRow["status"] }) { const styles: Record = { draft: "bg-gray-100 text-gray-600", sent: "bg-blue-100 text-blue-700", paid: "bg-emerald-100 text-emerald-700", overdue: "bg-red-100 text-red-700", cancelled: "bg-gray-100 text-gray-500", }; return ( {INVOICE_STATUS_LABELS[status]} ); } function formatDate(dateStr: string): string { const d = new Date(dateStr + "T00:00:00"); return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }); } export default function InvoicesListView({ invoices, filter, onFilterChange, onNewInvoice, onOpenInvoice, orgName, }: { invoices: InvoiceRow[]; filter: InvoiceListFilter; onFilterChange: (filter: InvoiceListFilter) => void; onNewInvoice: () => void; onOpenInvoice: (id: string) => void; orgName: string; }) { const [selected, setSelected] = useState>(new Set()); const [showSendModal, setShowSendModal] = useState(false); // Reset selection when filter or invoices change useEffect(() => { setSelected(new Set()); }, [filter, invoices.length]); const toggleSelect = (id: string) => { setSelected((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); }; const toggleSelectAll = () => { if (selected.size === invoices.length) { setSelected(new Set()); } else { setSelected(new Set(invoices.map((i) => i.id))); } }; const selectedInvoices = invoices.filter((i) => selected.has(i.id)); const sendableInvoices = selectedInvoices.filter((i) => i.client_email); const handleSendSelected = () => { setShowSendModal(true); }; const handleSendSuccess = () => { setShowSendModal(false); setSelected(new Set()); }; return (
{/* Header */}

Invoices

Create and manage your invoices

{/* Send selected */} {sendableInvoices.length > 0 && ( )}
{/* Filter Tabs */}
{FILTERS.map((f) => ( ))}
{/* AI Invoice Chase — only show when overdue filter is active or there are overdue invoices */} {(filter === "overdue" || invoices.some((i) => i.status === "overdue")) && ( )} {/* Table */}
{invoices.length === 0 ? (

No invoices found

{filter !== "all" ? "Try a different filter" : "Create your first invoice to get started"}

) : (
{invoices.map((invoice) => { const displayTotal = invoice.total_cents > 0 ? `$${centsToDecimal(invoice.total_cents)}` : invoice.amount != null ? `$${invoice.amount.toFixed(2)}` : "$0.00"; return ( ); })}
0} onChange={toggleSelectAll} className="rounded border-gray-300 text-[#1D9E75] focus:ring-[#1D9E75] cursor-pointer" /> Invoice # Client Issue Date Due Date Amount Status
toggleSelect(invoice.id)} onClick={(e) => e.stopPropagation()} className="rounded border-gray-300 text-[#1D9E75] focus:ring-[#1D9E75] cursor-pointer" /> {formatDate(invoice.issue_date)} {formatDate(invoice.due_date)} {displayTotal}
)}
{/* Send Modal */} {showSendModal && sendableInvoices.length > 0 && ( ({ id: i.id, invoice_number: i.invoice_number || "Draft", client_name: i.client_name || "", client_email: i.client_email || "", total: i.total_cents > 0 ? `$${centsToDecimal(i.total_cents)}` : i.amount != null ? `$${i.amount.toFixed(2)}` : "$0.00", }))} orgName={orgName} onClose={() => setShowSendModal(false)} onSuccess={handleSendSuccess} /> )}
); }