import { RiAttachment2, RiChat1Line, RiGroupLine, RiTimeLine, } from "@remixicon/react"; import type { ColumnDef } from "@tanstack/react-table"; import Image from "next/image"; import Link from "next/link"; import { DEFAULT_TRANSACTIONS_COLUMN_ORDER } from "@/features/transactions/lib/column-order"; import { CategoryIconBadge, EstablishmentLogo, } from "@/shared/components/entity-avatar"; import MoneyValues from "@/shared/components/money-values"; import { TransactionTypeBadge } from "@/shared/components/transaction-type-badge"; import { Avatar, AvatarFallback, AvatarImage, } from "@/shared/components/ui/avatar"; import { Badge } from "@/shared/components/ui/badge"; import { Checkbox } from "@/shared/components/ui/checkbox"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/shared/components/ui/tooltip"; import { resolveLogoSrc } from "@/shared/lib/logo"; import { getAvatarSrc } from "@/shared/lib/payers/utils"; import { formatDate } from "@/shared/utils/date"; import { getConditionIcon, getPaymentMethodIcon } from "@/shared/utils/icons"; import { cn } from "@/shared/utils/ui"; import type { TransactionItem } from "../types"; import { TransactionActionsMenu } from "./transaction-actions-menu"; import { TransactionSettlementButton } from "./transaction-settlement-button"; type BuildColumnsArgs = { currentUserId: string; noteAsColumn: boolean; onEdit?: (item: TransactionItem) => void; onCopy?: (item: TransactionItem) => void; onImport?: (item: TransactionItem) => void; onConfirmDelete?: (item: TransactionItem) => void; onViewDetails?: (item: TransactionItem) => void; onRefund?: (item: TransactionItem) => void; onToggleSettlement?: (item: TransactionItem) => void; onAnticipate?: (item: TransactionItem) => void; onViewAnticipationHistory?: (item: TransactionItem) => void; isSettlementLoading: (id: string) => boolean; showActions: boolean; columnOrder?: string[] | null; }; function getPaymentMethodTableLabel(method: string) { if (method === "Transferência bancária") return "Transf. bancária"; return method; } const FIXED_START_IDS = ["select", "purchaseDate"]; const FIXED_END_IDS = ["actions"]; function getColumnId(col: ColumnDef): string { const c = col as { id?: string; accessorKey?: string }; return c.id ?? c.accessorKey ?? ""; } function reorderColumnsByPreference( columns: ColumnDef[], orderPreference: string[] | null | undefined, ): ColumnDef[] { if (!orderPreference || orderPreference.length === 0) return columns; const order = orderPreference; const fixedStart: ColumnDef[] = []; const reorderable: ColumnDef[] = []; const fixedEnd: ColumnDef[] = []; for (const col of columns) { const id = getColumnId(col as ColumnDef); if (FIXED_START_IDS.includes(id)) fixedStart.push(col); else if (FIXED_END_IDS.includes(id)) fixedEnd.push(col); else reorderable.push(col); } const sorted = [...reorderable].sort((a, b) => { const idA = getColumnId(a as ColumnDef); const idB = getColumnId(b as ColumnDef); const indexA = order.indexOf(idA); const indexB = order.indexOf(idB); if (indexA === -1 && indexB === -1) return 0; if (indexA === -1) return 1; if (indexB === -1) return -1; return indexA - indexB; }); return [...fixedStart, ...sorted, ...fixedEnd]; } function buildColumns({ currentUserId, noteAsColumn, onEdit, onCopy, onImport, onConfirmDelete, onViewDetails, onRefund, onToggleSettlement, onAnticipate, onViewAnticipationHistory, isSettlementLoading, showActions, }: BuildColumnsArgs): ColumnDef[] { const noop = () => undefined; const handleEdit = onEdit ?? noop; const handleCopy = onCopy ?? noop; const handleImport = onImport ?? noop; const handleConfirmDelete = onConfirmDelete ?? noop; const handleViewDetails = onViewDetails ?? noop; const handleRefund = onRefund ?? noop; const handleToggleSettlement = onToggleSettlement ?? noop; const handleAnticipate = onAnticipate ?? noop; const handleViewAnticipationHistory = onViewAnticipationHistory ?? noop; const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Selecionar todos" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Selecionar linha" /> ), enableSorting: false, enableHiding: false, }, { id: "purchaseDate", accessorKey: "purchaseDate", header: () => null, cell: () => null, }, { accessorKey: "name", header: "Estabelecimento", cell: ({ row }) => { const { name, purchaseDate, installmentCount, currentInstallment, paymentMethod, dueDate, note, isDivided, isAnticipated, hasAttachments, } = row.original; const installmentBadge = currentInstallment && installmentCount ? `${currentInstallment} de ${installmentCount}` : null; const isBoleto = paymentMethod === "Boleto" && dueDate; const dueDateLabel = isBoleto && dueDate ? `Venc. ${formatDate(dueDate)}` : null; const hasNote = Boolean(note?.trim().length); const isLastInstallment = currentInstallment === installmentCount && installmentCount && installmentCount > 1; return ( {formatDate(purchaseDate)} {dueDateLabel ? ( {dueDateLabel} ) : null} {name} {name} {isDivided && ( Dividido entre pessoas Dividido entre pessoas )} {isLastInstallment ? ( Última parcela Última parcela Última parcela! ) : null} {installmentBadge ? ( {installmentBadge} ) : null} {isAnticipated && ( Parcela antecipada Parcela antecipada )} {!noteAsColumn && hasNote ? ( Ver anotação {note} ) : null} {hasAttachments ? ( Possui anexos Possui anexos ) : null} ); }, }, { accessorKey: "transactionType", header: "Transação", cell: ({ row }) => { const type = row.original.categoriaName === "Saldo inicial" ? "Saldo inicial" : row.original.transactionType; return ( ); }, }, { accessorKey: "amount", header: "Valor", cell: ({ row }) => { const isReceita = row.original.transactionType === "Receita"; const isTransfer = row.original.transactionType === "Transferência"; const isIncomingTransfer = isTransfer && Number(row.original.amount) > 0; return ( ); }, }, { accessorKey: "condition", header: "Condição", cell: ({ row }) => { const condition = row.original.condition; const icon = getConditionIcon(condition); return ( {icon} {condition} ); }, }, { accessorKey: "paymentMethod", header: "Forma de Pagamento", cell: ({ row }) => { const method = row.original.paymentMethod; const icon = getPaymentMethodIcon(method); return ( {icon} {getPaymentMethodTableLabel(method)} ); }, }, { accessorKey: "categoriaName", header: "Categoria", cell: ({ row }) => { const { categoriaName, categoriaIcon } = row.original; if (!categoriaName) { return ; } return ( {categoriaName} ); }, }, { accessorKey: "pagadorName", header: "Pessoa", cell: ({ row }) => { const { payerId, pagadorName, pagadorAvatar } = row.original; const label = pagadorName?.trim() || "Sem pessoa"; const displayName = label.split(/\s+/)[0] ?? label; const avatarSrc = getAvatarSrc(pagadorAvatar); const initial = displayName.charAt(0).toUpperCase() || "?"; const content = ( <> {initial} {displayName} ); if (!payerId) { return ( {content} ); } return ( {content} ); }, }, { id: "contaCartao", header: "Conta/Cartão", cell: ({ row }) => { const { cartaoName, contaName, cartaoLogo, contaLogo, cardId, accountId, userId, } = row.original; const isCartao = Boolean(cartaoName); const label = cartaoName ?? contaName; const logoSrc = resolveLogoSrc(cartaoLogo ?? contaLogo); const href = cardId ? `/cards/${cardId}/invoice` : accountId ? `/accounts/${accountId}/statement` : null; const isOwnData = userId === currentUserId; const content = ( {logoSrc && ( {label} )} {label} ); if (!isOwnData || !href) { return ( {content} {isCartao ? "Cartão" : "Conta"}: {label} ); } return ( {content} {isCartao ? "Cartão" : "Conta"}: {label} ); }, }, ]; if (noteAsColumn) { const accountCardIndex = columns.findIndex((c) => c.id === "contaCartao"); const noteColumn: ColumnDef = { accessorKey: "note", header: "Anotação", cell: ({ row }) => { const note = row.original.note; if (!note?.trim()) return ; return ( {note} ); }, }; columns.splice(accountCardIndex, 0, noteColumn); } if (showActions) { columns.push({ id: "actions", header: "Ações", enableSorting: false, cell: ({ row }) => (
), }); } return columns; } export function getTransactionColumns( args: BuildColumnsArgs, ): ColumnDef[] { const built = buildColumns(args); const order = args.columnOrder?.length ? args.columnOrder : DEFAULT_TRANSACTIONS_COLUMN_ORDER; return reorderColumnsByPreference(built, order); }