"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([])} />
)}
)
}