'use client' import { useState, useEffect, useMemo, useRef } from 'react' import { useAccounts } from '@/lib/reference-data/hooks' import { useTranslations } from 'next-intl' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { ArrowLeft, Loader2, Play, FileText, Link2, Calendar, Landmark, AlertTriangle, } from 'lucide-react' import { formatCurrency } from '@/lib/utils' import { summarizeByCurrency } from '@/lib/import/bank-file/currency-summary' import type { BankFileParseResult, BankFileDuplicateInfo } from '@/lib/import/bank-file/types' interface BankAccount { account_number: string account_name: string } interface BankFileConfirmStepProps { parseResult: BankFileParseResult duplicateInfo?: BankFileDuplicateInfo | null onExecute: (options: { skip_duplicates: boolean; auto_categorize: boolean; settlement_account?: string }) => void onBack: () => void isLoading: boolean } export default function BankFileConfirmStep({ parseResult, duplicateInfo, onExecute, onBack, isLoading, }: BankFileConfirmStepProps) { const t = useTranslations('transactions') const { transactions, stats, date_from, date_to, issues } = parseResult const refsCount = transactions.filter((tx) => tx.reference).length const warnings = issues.filter((i) => i.severity === 'warning') // Same per-currency grouping as the preview step: parser-level totals sum // across currencies, which misleads on Wise/camt.053 multi-currency files. const currencyTotals = summarizeByCurrency(transactions) // Advisory: clamp so a stale preview can never produce a negative CTA // count. Execute stays authoritative; the copy says rows are skipped // automatically rather than promising an exact final number. const duplicateCount = Math.min(Math.max(duplicateInfo?.duplicate_count ?? 0, 0), stats.parsed_rows) const [selectedAccount, setSelectedAccount] = useState('1930') // Active 19xx accounts from the session-cached chart (lib/reference-data): // the account select is populated on the first paint. const { accounts } = useAccounts() const bankAccounts = useMemo( () => accounts .filter((a) => a.account_number >= '1900' && a.account_number <= '1999') .sort((a, b) => a.account_number.localeCompare(b.account_number)) .map((a) => ({ account_number: a.account_number, account_name: a.account_name })), [accounts], ) // Default to 1930 if available, otherwise the first account (once). const defaultedRef = useRef(false) useEffect(() => { if (defaultedRef.current || bankAccounts.length === 0) return defaultedRef.current = true const has1930 = bankAccounts.some((a) => a.account_number === '1930') if (!has1930) setSelectedAccount(bankAccounts[0].account_number) }, [bankAccounts]) if (isLoading) { return (

Importerar transaktioner...

{stats.parsed_rows} transaktioner bearbetas

) } return (
{/* Summary */} Bekräfta import Granska sammanfattningen och importera transaktionerna. {/* Stats grid */}
Transaktioner

{stats.parsed_rows}

{stats.skipped_rows > 0 && (

{stats.skipped_rows} rader hoppades över

)}
Period

{date_from}: {date_to}

Inkomster
{(currencyTotals.length ? currencyTotals : [{ currency: 'SEK', total_income: 0, total_expenses: 0 }]).map((row) => (

{formatCurrency(row.total_income, row.currency)}

))}
Utgifter
{(currencyTotals.length ? currencyTotals : [{ currency: 'SEK', total_income: 0, total_expenses: 0 }]).map((row) => (

{formatCurrency(row.total_expenses, row.currency)}

))}
{/* Bank account selector */} {bankAccounts.length > 1 && (

Välj vilket bankkonto transaktionerna ska bokföras mot.

)} {/* Additional info */} {refsCount > 0 && (
{refsCount} med OCR/referens
)}
{/* Duplicate rows: repeated here because the generic_csv path skips the preview step where the same card is shown. Advisory: ingest skips them automatically at execute. */} {duplicateCount > 0 && ( {t('import_duplicate_rows_title', { count: duplicateCount })} {t('import_duplicate_rows_body')} )} {/* Skipped rows: surfaced here because the manual-mapping path skips the preview step where these warnings would otherwise be shown. */} {warnings.length > 0 && ( {warnings.length} {warnings.length === 1 ? 'rad' : 'rader'} hoppades över Dessa rader kunde inte läsas och importeras inte. Kontrollera att inga transaktioner saknas.
{warnings.slice(0, 10).map((issue, i) => (

Rad {issue.row}: {issue.message}

))} {warnings.length > 10 && (

…och {warnings.length - 10} till

)}
)} {/* Actions */}
) }