import { useState, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Tag } from "lucide-react"; import type { RecentTransaction } from "../../shared/types"; import ContextMenu from "../shared/ContextMenu"; export interface CategoryTransactionsTableProps { transactions: RecentTransaction[]; onAddKeyword?: (transaction: RecentTransaction) => void; } type SortKey = "date" | "description" | "amount"; function formatAmount(amount: number, language: string): string { return new Intl.NumberFormat(language === "fr" ? "fr-CA" : "en-CA", { style: "currency", currency: "CAD", }).format(amount); } export default function CategoryTransactionsTable({ transactions, onAddKeyword, }: CategoryTransactionsTableProps) { const { t, i18n } = useTranslation(); const [sortKey, setSortKey] = useState("amount"); const [sortDir, setSortDir] = useState<"asc" | "desc">("desc"); const [menu, setMenu] = useState<{ x: number; y: number; tx: RecentTransaction } | null>(null); const sorted = useMemo(() => { const copy = [...transactions]; copy.sort((a, b) => { let cmp = 0; switch (sortKey) { case "date": cmp = a.date.localeCompare(b.date); break; case "description": cmp = a.description.localeCompare(b.description); break; case "amount": cmp = Math.abs(a.amount) - Math.abs(b.amount); break; } return sortDir === "asc" ? cmp : -cmp; }); return copy; }, [transactions, sortKey, sortDir]); function toggleSort(key: SortKey) { if (sortKey === key) setSortDir((d) => (d === "asc" ? "desc" : "asc")); else { setSortKey(key); setSortDir("desc"); } } const handleContextMenu = (e: React.MouseEvent, tx: RecentTransaction) => { if (!onAddKeyword) return; e.preventDefault(); setMenu({ x: e.clientX, y: e.clientY, tx }); }; const header = (key: SortKey, label: string, align: "left" | "right") => ( toggleSort(key)} className={`${align === "right" ? "text-right" : "text-left"} px-3 py-2 font-medium text-[var(--muted-foreground)] cursor-pointer hover:text-[var(--foreground)] select-none`} > {label} {sortKey === key && {sortDir === "asc" ? "▲" : "▼"}} ); return (
{header("date", t("transactions.date"), "left")} {header("description", t("transactions.description"), "left")} {header("amount", t("transactions.amount"), "right")} {sorted.length === 0 ? ( ) : ( sorted.map((tx) => ( handleContextMenu(e, tx)} className="border-b border-[var(--border)] last:border-0 hover:bg-[var(--muted)]/40" > )) )}
{t("reports.empty.noData")}
{tx.date} {tx.description} = 0 ? "var(--positive, #10b981)" : "var(--foreground)", }} > {formatAmount(tx.amount, i18n.language)}
{menu && onAddKeyword && ( setMenu(null)} items={[ { icon: , label: t("reports.keyword.addFromTransaction"), onClick: () => { onAddKeyword(menu.tx); }, }, ]} /> )}
); }