'use client' import { useState } from 'react' import { useTranslations } from 'next-intl' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { ArrowLeft, ArrowRight, AlertTriangle, Calendar, FileText, Scale } from 'lucide-react' import { formatCurrency, cn } from '@/lib/utils' import { roundOre } from '@/lib/money' import type { SkattekontoFileParseResult } from '@/lib/import/skattekonto-file/types' interface SkattekontoFilePreviewStepProps { parseResult: SkattekontoFileParseResult duplicateIndexes: number[] promotionIndexes: number[] orgNumberMismatch: boolean isLoading: boolean onExecute: () => void onBack: () => void } const PREVIEW_ROW_LIMIT = 100 export default function SkattekontoFilePreviewStep({ parseResult, duplicateIndexes, promotionIndexes, orgNumberMismatch, isLoading, onExecute, onBack, }: SkattekontoFilePreviewStepProps) { const t = useTranslations('import') const [mismatchConfirmed, setMismatchConfirmed] = useState(false) const [sumGapConfirmed, setSumGapConfirmed] = useState(false) const { rows, stats, issues, date_from, date_to, opening_saldo, closing_saldo, events_sum, sum_difference, sum_valid, } = parseResult const duplicateSet = new Set(duplicateIndexes) const promotionSet = new Set(promotionIndexes) const newCount = rows.length - duplicateIndexes.length const warnings = issues.filter((i) => i.severity !== 'error') // A statement that does not sum (truncated, filtered, unreadable rows) is // a confirm gate, not a block: nothing is booked at import and every event // is reviewed on the skattekonto page, so importing what IS in the file is // safe. The gate exists so the user knows the picture is incomplete. const sumGap = sum_valid === false const sumGapHasFigures = opening_saldo !== null && closing_saldo !== null && events_sum !== null && sum_difference !== null const importBlocked = (orgNumberMismatch && !mismatchConfirmed) || (sumGap && !sumGapConfirmed) return (
{stats.parsed_rows}
{stats.skipped_rows > 0 && ({t('skattekonto_preview_skipped', { count: stats.skipped_rows })}
)}{date_from || '-'} – {date_to || '-'}
{closing_saldo !== null ? formatCurrency(closing_saldo) : '-'}
{t('skattekonto_org_mismatch_body', { orgNumber: parseResult.org_number ?? '?', companyName: parseResult.company_name ?? '?', })}
{t('skattekonto_sum_gap_no_saldo')}
)}{stats.unreadable_amount_rows > 0 ? t('skattekonto_sum_gap_body_unreadable', { count: stats.unreadable_amount_rows }) : t('skattekonto_sum_gap_body')}
{t('skattekonto_duplicates_note', { count: duplicateIndexes.length })}
)} {/* What happens after import: nothing is booked automatically, and an event that already has a 1630 verifikat (a deposit booked from the bank side) is offered as a link, not a second booking. Answers the "some of these are already booked" question before the click. */}{t('skattekonto_after_import_note')}
{warnings.length > 0 && ({issue.row > 0 ? `${t('skattekonto_issue_row', { row: issue.row })}: ` : ''} {issue.message}
))}{t('skattekonto_preview_truncated', { shown: PREVIEW_ROW_LIMIT, total: rows.length, })}
)}