'use client' import { useState, useEffect, useCallback } from 'react' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog' import { useToast } from '@/components/ui/use-toast' import { formatCurrency, formatDate } from '@/lib/utils' import { ArrowUpRight, ArrowDownRight, Check, Paperclip, ChevronDown, ChevronUp, AlertTriangle } from 'lucide-react' import { getDefaultAccountForCategory } from '@/lib/bookkeeping/category-mapping' import type { BookingTemplate } from '@/lib/bookkeeping/booking-templates' import JournalEntryPreview from './JournalEntryPreview' import AccountCombobox from '@/components/bookkeeping/AccountCombobox' import DocumentUploadZone from '@/components/bookkeeping/DocumentUploadZone' import type { UploadedFile } from '@/components/bookkeeping/DocumentUploadZone' import VatTreatmentSelect from './VatTreatmentSelect' import { VAT_TREATMENT_OPTIONS } from './transaction-types' import type { TransactionWithInvoice } from './transaction-types' import type { TransactionCategory, VatTreatment, BASAccount, EntityType } from '@/types' interface QuickReviewDialogProps { open: boolean onOpenChange: (open: boolean) => void transaction: TransactionWithInvoice | null category: TransactionCategory | null categoryLabel: string defaultAccount: string defaultVat: VatTreatment | 'none' entityType?: EntityType template?: BookingTemplate | null templateId?: string onConfirm: ( id: string, category: TransactionCategory, vatTreatment: VatTreatment | undefined, accountOverride: string | undefined, templateId?: string ) => Promise onChangeTemplate?: () => void } export default function QuickReviewDialog({ open, onOpenChange, transaction, category, categoryLabel, defaultAccount, defaultVat, entityType, template, templateId, onConfirm, onChangeTemplate, }: QuickReviewDialogProps) { const { toast } = useToast() const [accountOverride, setAccountOverride] = useState(defaultAccount) const [vatTreatment, setVatTreatment] = useState(defaultVat) const [accounts, setAccounts] = useState([]) const [isProcessing, setIsProcessing] = useState(false) const [error, setError] = useState(null) const [uploadedFiles, setUploadedFiles] = useState([]) const [showUploadZone, setShowUploadZone] = useState(false) const [showVatDropdown, setShowVatDropdown] = useState(false) // Handle account changes — clear VAT for liability/equity accounts (class 2) const handleAccountChange = useCallback((account: string) => { setAccountOverride(account) if (account.startsWith('2')) { setVatTreatment('none') } }, []) // Fetch accounts on mount useEffect(() => { async function fetchAccounts() { try { const res = await fetch('/api/bookkeeping/accounts') const data = await res.json() if (data.accounts) { setAccounts(data.accounts) } } catch { // Non-critical } } fetchAccounts() }, []) if (!transaction || !category) return null const isIncome = transaction.amount > 0 const isLiabilityAccount = accountOverride.startsWith('2') async function handleConfirm() { if (!category || !transaction) return setIsProcessing(true) setError(null) try { const resolvedVat = vatTreatment === 'none' ? undefined : vatTreatment const catDefault = getDefaultAccountForCategory(category) const override = accountOverride && accountOverride !== catDefault ? accountOverride : undefined const journalEntryId = await onConfirm(transaction.id, category, resolvedVat, override, templateId) // Link uploaded documents to the journal entry if (journalEntryId && uploadedFiles.length > 0) { const filesToLink = uploadedFiles.filter((f) => f.status === 'uploaded' && f.id) let linkFailCount = 0 for (const file of filesToLink) { try { await fetch(`/api/documents/${file.id}/link`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ journal_entry_id: journalEntryId }), }) } catch { linkFailCount++ } } if (linkFailCount > 0) { toast({ title: 'Underlag kunde inte bifogas', description: `${linkFailCount} fil(er) kunde inte länkas till verifikationen.`, variant: 'destructive', }) } } setUploadedFiles([]) setShowUploadZone(false) } catch { setError('Ett fel uppstod vid bokföring.') setIsProcessing(false) } } return ( { if (!o) { setUploadedFiles([]) setShowUploadZone(false) } onOpenChange(o) }}> Granska bokföring Kontrollera konto och moms innan du bokför {/* Transaction summary */}
{isIncome ? ( ) : ( )}

{transaction.description}

{formatDate(transaction.date)}

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

{/* Template or Category */}
{template ? template.name_sv : categoryLabel} {onChangeTemplate && ( )}
{/* Template special rules */} {template?.special_rules_sv && (

{template.special_rules_sv}

)} {/* Deductibility note */} {template?.deductibility_note_sv && (

{template.deductibility_note_sv}

)} {/* Reverse charge warning */} {template?.requires_vat_registration_data && (

Omvänd skattskyldighet kräver leverantörens momsregistreringsnummer och land.

)} {/* Journal entry preview */} {/* Account */}
{/* VAT treatment */}
{isLiabilityAccount ? (

Ingen moms för skuld-/eget kapital-konton

) : showVatDropdown ? ( ) : (

{VAT_TREATMENT_OPTIONS.find(o => o.value === vatTreatment)?.label || 'Ingen moms'} {' '}

)}
{/* Document upload */}
{showUploadZone && (
)}
{error && (
{error}
)} {/* Actions */}
) }