"use client" import { BulkActionsMenu } from "@/components/transactions/bulk-actions" import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { calcTotalPerCurrency } from "@/lib/stats" import { cn, formatCurrency } from "@/lib/utils" import { Category, Project, Transaction } from "@prisma/client" import { formatDate } from "date-fns" import { ArrowDownIcon, ArrowUpIcon, File } from "lucide-react" import { useRouter, useSearchParams } from "next/navigation" import { useEffect, useState } from "react" export const transactionsTable = [ { name: "Name", db: "name", classes: "font-medium max-w-[300px] min-w-[120px] overflow-hidden", sortable: true, }, { name: "Merchant", db: "merchant", classes: "max-w-[200px] max-h-[20px] min-w-[120px] overflow-hidden", sortable: true, }, { name: "Date", db: "issuedAt", classes: "min-w-[100px]", format: (transaction: Transaction) => (transaction.issuedAt ? formatDate(transaction.issuedAt, "yyyy-MM-dd") : ""), sortable: true, }, { name: "Project", db: "projectCode", format: (transaction: Transaction & { project: Project }) => transaction.projectCode ? ( {transaction.project?.name || ""} ) : ( "-" ), sortable: true, }, { name: "Category", db: "categoryCode", format: (transaction: Transaction & { category: Category }) => transaction.categoryCode ? ( {transaction.category?.name || ""} ) : ( "-" ), sortable: true, }, { name: "Files", db: "files", format: (transaction: Transaction) => (
{(transaction.files as string[]).length}
), sortable: false, }, { name: "Total", db: "total", classes: "text-right", format: (transaction: Transaction) => (
{transaction.total && transaction.currencyCode ? formatCurrency(transaction.total, transaction.currencyCode) : transaction.total} {transaction.convertedTotal && transaction.convertedCurrencyCode && transaction.convertedCurrencyCode !== transaction.currencyCode && ( ({formatCurrency(transaction.convertedTotal, transaction.convertedCurrencyCode)}) )}
), sortable: true, footer: (transactions: Transaction[]) => { const totalPerCurrency = calcTotalPerCurrency(transactions) return (
{Object.entries(totalPerCurrency).map(([currency, total]) => (
{formatCurrency(total, currency)}
))}
) }, }, ] export function TransactionList({ transactions }: { transactions: Transaction[] }) { const [selectedIds, setSelectedIds] = useState([]) const router = useRouter() const searchParams = useSearchParams() const [sorting, setSorting] = useState<{ field: string | null; direction: "asc" | "desc" | null }>(() => { const ordering = searchParams.get("ordering") if (!ordering) return { field: null, direction: null } const isDesc = ordering.startsWith("-") return { field: isDesc ? ordering.slice(1) : ordering, direction: isDesc ? "desc" : "asc", } }) const toggleAll = () => { if (selectedIds.length === transactions.length) { setSelectedIds([]) } else { setSelectedIds(transactions.map((transaction) => transaction.id)) } } const toggleOne = (e: React.MouseEvent, id: string) => { e.stopPropagation() if (selectedIds.includes(id)) { setSelectedIds(selectedIds.filter((item) => item !== id)) } else { setSelectedIds([...selectedIds, id]) } } const handleRowClick = (id: string) => { router.push(`/transactions/${id}`) } const handleSort = (field: string) => { let newDirection: "asc" | "desc" | null = "asc" if (sorting.field === field) { if (sorting.direction === "asc") newDirection = "desc" else if (sorting.direction === "desc") newDirection = null } setSorting({ field: newDirection ? field : null, direction: newDirection, }) } useEffect(() => { const params = new URLSearchParams(searchParams.toString()) if (sorting.field && sorting.direction) { const ordering = sorting.direction === "desc" ? `-${sorting.field}` : sorting.field params.set("ordering", ordering) } else { params.delete("ordering") } router.push(`/transactions?${params.toString()}`) }, [sorting]) const getSortIcon = (field: string) => { if (sorting.field !== field) return null return sorting.direction === "asc" ? ( ) : sorting.direction === "desc" ? ( ) : null } return (
{transactionsTable.map((field) => ( field.sortable && handleSort(field.db)} > {field.name} {field.sortable && getSortIcon(field.db)} ))} {transactions.map((transaction: any) => ( handleRowClick(transaction.id)} > e.stopPropagation()}> { if (checked !== "indeterminate") { toggleOne({ stopPropagation: () => {} } as React.MouseEvent, transaction.id) } }} /> {transactionsTable.map((field) => ( {field.format ? field.format(transaction) : transaction[field.db]} ))} ))} {transactionsTable.map((field) => ( {field.footer ? field.footer(transactions) : ""} ))}
{selectedIds.length > 0 && ( setSelectedIds([])} /> )}
) }