import { Link, useNavigate } from "@tanstack/react-router"; import { ChevronRight } from "lucide-react"; import type { Invoice } from "@rubis/shared"; import { StatusBadge } from "@/components/ui/StatusBadge"; import { formatEuros, formatDate, formatDueDelta, isOverdue } from "@/lib/format"; import { cn } from "@/lib/utils"; /** Forme enrichie utilisée par la liste : invoice + nom client + nom plan. */ export type InvoiceListItem = Invoice & { clientName: string; planName: string | null; /** Label de statut serveur, ex: "Relance J+3 envoyée". Override visuel. */ statusLabel?: string; }; type InvoiceTableProps = { invoices: InvoiceListItem[]; className?: string; }; /** * Table desktop des factures. * * Décisions visuelles : * - Échéance dépassée en bold (cf. wireframe 2.4) * - **Ligne entière cliquable** via onClick + role="link" + onKeyDown * (le chevron de droite reste un vrai pour le right-click "ouvrir * dans un nouvel onglet" + middle-click) * - Statut dans une chip sémantique (StatusBadge) * - Pas de checkbox actions-en-lot en V1 (à venir avec le backend) */ export function InvoiceTable({ invoices, className }: InvoiceTableProps) { const navigate = useNavigate(); const goToInvoice = (id: string): void => { void navigate({ to: "/factures/$id", params: { id } }); }; return (
{invoices.map((invoice) => { const overdue = isOverdue(invoice.dueDate); return ( goToInvoice(invoice.id)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); goToInvoice(invoice.id); } }} className={cn( "border-t border-line first:border-t-0 cursor-pointer", "transition-colors hover:bg-cream-2/40", "focus-visible:outline-none focus-visible:bg-cream focus-visible:ring-2 focus-visible:ring-rubis-glow focus-visible:ring-inset", )} > ); })}
Client N° facture Montant Échéance Statut Plan
{invoice.clientName} {invoice.numero} {formatEuros(invoice.amountTtcCents)} {formatDate(invoice.dueDate)} {formatDueDelta(invoice.dueDate)} {invoice.planName ?? — aucun} {/* Chevron explicite — vrai pour le right-click / middle-click "ouvrir dans nouvel onglet". On stoppe la propagation pour ne pas double-naviguer via le row click. */} e.stopPropagation()} className="inline-flex size-7 items-center justify-center rounded-default text-ink-3 hover:bg-cream hover:text-rubis" aria-label={`Voir la facture ${invoice.numero}`} >
); }