'use client'; import { format } from 'date-fns'; import { Calendar, CreditCard, Eye, FileText, MoreHorizontal, Send, Trash2, User, } from 'lucide-react'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { ListCard, ListCardAvatar, ListCardMeta } from '@/components/shared/list-card'; import { cn } from '@/lib/utils'; import type { InvoiceRow } from './invoice-columns'; const STATUS_COLORS: Record = { draft: 'bg-gray-100 text-gray-700 border-gray-200', sent: 'bg-blue-100 text-blue-700 border-blue-200', paid: 'bg-green-100 text-green-700 border-green-200', overdue: 'bg-red-100 text-red-700 border-red-200', cancelled: 'bg-gray-100 text-gray-500 border-gray-200', }; /** * Accent bar encodes payment completeness using `status`: * paid → green * overdue → orange (past-due unpaid) * sent → slate (awaiting payment, not yet overdue) * draft → slate-200 * other → slate-300 */ const STATUS_ACCENT: Record = { paid: 'bg-emerald-400', overdue: 'bg-orange-400', sent: 'bg-slate-300', draft: 'bg-slate-200', cancelled: 'bg-slate-200', }; function formatAmount(total: string, currency: string): string { try { return new Intl.NumberFormat('en', { style: 'currency', currency }).format(Number(total)); } catch { return `${currency} ${total}`; } } interface InvoiceCardProps { invoice: InvoiceRow; portSlug: string; onSend?: (invoice: InvoiceRow) => void; onRecordPayment?: (invoice: InvoiceRow) => void; onDelete?: (invoice: InvoiceRow) => void; } export function InvoiceCard({ invoice, portSlug, onSend, onRecordPayment, onDelete, }: InvoiceCardProps) { const statusColor = STATUS_COLORS[invoice.status] ?? STATUS_COLORS.draft; const accentClass = STATUS_ACCENT[invoice.status] ?? 'bg-slate-300'; let dueDateFormatted: string | null = null; try { dueDateFormatted = format(new Date(invoice.dueDate), 'MMM d, yyyy'); } catch { dueDateFormatted = invoice.dueDate; } const amountFormatted = formatAmount(invoice.total, invoice.currency); return ( View {invoice.pdfFileId ? ( View PDF ) : null} {invoice.status === 'draft' && onSend ? ( onSend(invoice)}> Send ) : null} {(invoice.status === 'sent' || invoice.status === 'overdue') && onRecordPayment ? ( onRecordPayment(invoice)}> Record Payment ) : null} {invoice.status === 'draft' && onDelete ? ( onDelete(invoice)}> Delete ) : null} } >
} />
{/* Title row: invoice number + spacer for actions */}

{invoice.invoiceNumber}

{/* Client name */}

{invoice.clientName}

{/* Amount - prominent */}

{amountFormatted}

{/* Due date */} {dueDateFormatted ? (
}> Due {dueDateFormatted}
) : null} {/* Status pill */}
{invoice.status}
); }