'use client' import { useTranslations } from 'next-intl' import { motion } from 'framer-motion' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Checkbox } from '@/components/ui/checkbox' import { DataListRow, DataListPrimary, DataListMeta, DataListMetaSeparator, } from '@/components/ui/data-list' import { cn, formatCurrency, formatDate } from '@/lib/utils' import { AlertCircle, ArrowUpRight, ArrowDownRight, FileText, Link2, Loader2, Trash2, } from 'lucide-react' import { TransactionAttachmentIndicator } from './TransactionAttachmentIndicator' import type { TransactionWithInvoice, CategorizeHandler } from './transaction-types' interface TransactionInboxCardProps { transaction: TransactionWithInvoice /** When set, this bank tx looks like the bank side of a 1930↔1630 * transfer that the user will later see on /skattekonto. */ skvCounterpartDate?: string processingId: string | null isBatchMode: boolean isSelected: boolean entityType?: string onCategorize: CategorizeHandler /** Confirm an auto-detected invoice match (1-click shortcut). */ onOpenMatchDialog: (transaction: TransactionWithInvoice) => void /** Open the manual picker — routes to customer or supplier picker by amount sign. */ onOpenMatchInvoicePicker: (transaction: TransactionWithInvoice) => void onOpenCategoryDialog: (transaction: TransactionWithInvoice) => void onDelete?: (id: string) => void onToggleSelect: (id: string) => void onAnimationComplete?: (id: string) => void } export default function TransactionInboxCard({ transaction, skvCounterpartDate, processingId, isBatchMode, isSelected, onOpenMatchDialog, onOpenMatchInvoicePicker, onOpenCategoryDialog, onDelete, onToggleSelect, onAnimationComplete, }: TransactionInboxCardProps) { const t = useTranslations('tx_inbox_card') const isProcessing = processingId === transaction.id const isDisabled = processingId !== null && processingId !== transaction.id const isIncome = transaction.amount > 0 const hasInvoiceMatch = !!transaction.potential_invoice && !transaction.invoice_id const hasSupplierInvoiceMatch = !!transaction.potential_supplier_invoice && !transaction.supplier_invoice_id const isUncategorized = transaction.is_business === null && !transaction.journal_entry_id const showCheckbox = isBatchMode && isUncategorized const isDeletable = !transaction.journal_entry_id // Primary action: invoice/supplier-invoice match keeps the 1-click shortcut; // otherwise the user opens the template picker. const primaryAction = (() => { if (hasInvoiceMatch) { return ( ) } if (hasSupplierInvoiceMatch) { return ( ) } return ( ) })() // Manual invoice-match affordance. Hidden once an auto-detected match is // already shown as the primary button — having both makes the row noisy. const showInvoiceMatchButton = isDeletable && !hasInvoiceMatch && !hasSupplierInvoiceMatch const invoiceMatchLabel = isIncome ? 'Matcha mot kundfaktura' : 'Matcha mot leverantörsfaktura' return ( { if (typeof definition === 'object' && 'opacity' in definition && definition.opacity === 0) { onAnimationComplete?.(transaction.id) } }} > onToggleSelect(transaction.id) : undefined} leading={ showCheckbox ? ( onToggleSelect(transaction.id)} onClick={(e) => e.stopPropagation()} aria-label="Välj transaktion" /> ) : ( {isIncome ? ( ) : ( )} ) } trailing={ <>

{isIncome ? '+' : ''} {formatCurrency(transaction.amount, transaction.currency)}

{transaction.currency !== 'SEK' && transaction.amount_sek != null && (

{formatCurrency(transaction.amount_sek)}

)}
{!isBatchMode && ( <> {primaryAction} {showInvoiceMatchButton && ( )} {isDeletable && onDelete && ( )} )} } >
{transaction.description}
{formatDate(transaction.date)} {skvCounterpartDate && ( <> Möjlig 1930↔1630 )}
) }