'use client' import { useState, useMemo } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { AlertTriangle, Check, X, Building, User, Wine, Utensils, Globe, ChevronUp, ChevronDown, Loader2, } from 'lucide-react' import { formatCurrency, formatDate } from '@/lib/utils' import { calculateReceiptSplit, getDefaultClassification } from '../lib/receipt-categorizer' import { calculateRepresentationLimits } from '../lib/receipt-utils' import ReceiptLineItemRow from './ReceiptLineItemRow' import type { Receipt, ReceiptLineItem, TransactionCategory, ConfirmLineItemInput } from '@/types' interface ReceiptReviewViewProps { receipt: Receipt & { line_items: ReceiptLineItem[] } onConfirm: (data: { line_items: ConfirmLineItemInput[] representation_persons?: number representation_purpose?: string }) => Promise onCancel: () => void onFindMatches?: () => void } export default function ReceiptReviewView({ receipt, onConfirm, onCancel, onFindMatches, }: ReceiptReviewViewProps) { // Initialize line items with their current state const [lineItems, setLineItems] = useState(receipt.line_items || []) const [isProcessing, setIsProcessing] = useState(false) const [showImage, setShowImage] = useState(false) // Restaurant representation state const [representationPersons, setRepresentationPersons] = useState( receipt.representation_persons || undefined ) const [representationPurpose, setRepresentationPurpose] = useState( receipt.representation_purpose || '' ) // Get default classification info const defaultClassification = getDefaultClassification( receipt.is_restaurant, receipt.is_systembolaget ) // Calculate split summary const splitSummary = useMemo(() => { return calculateReceiptSplit(lineItems.map(item => ({ lineTotal: item.line_total, is_business: item.is_business, }))) }, [lineItems]) // Calculate representation limits if restaurant const representationCalc = useMemo(() => { if (!receipt.is_restaurant || !representationPersons || !receipt.total_amount) return null return calculateRepresentationLimits(receipt.total_amount, representationPersons) }, [receipt.is_restaurant, receipt.total_amount, representationPersons]) // Toggle business status for a line item const handleToggleBusiness = (id: string, isBusiness: boolean) => { setLineItems((items) => items.map((item) => item.id === id ? { ...item, is_business: isBusiness, category: isBusiness ? item.category : null } : item ) ) } // Change category for a line item const handleCategoryChange = (id: string, category: TransactionCategory) => { setLineItems((items) => items.map((item) => (item.id === id ? { ...item, category } : item)) ) } // Mark all as business const handleAllBusiness = () => { setLineItems((items) => items.map((item) => ({ ...item, is_business: true, category: item.category || 'expense_other', })) ) } // Mark all as private const handleAllPrivate = () => { setLineItems((items) => items.map((item) => ({ ...item, is_business: false, category: null, })) ) } // Confirm and save const handleConfirm = async () => { // Validate restaurant representation if (receipt.is_restaurant && splitSummary.businessTotal > 0) { if (!representationPersons || representationPersons < 1) { alert('Ange antal personer för restaurangrepresentation') return } if (!representationPurpose.trim()) { alert('Ange syfte för restaurangrepresentation') return } } setIsProcessing(true) try { await onConfirm({ line_items: lineItems.map((item) => ({ id: item.id, is_business: item.is_business ?? false, category: item.category || undefined, bas_account: item.bas_account || undefined, })), representation_persons: representationPersons, representation_purpose: representationPurpose.trim() || undefined, }) } catch (error) { console.error('Confirm error:', error) } finally { setIsProcessing(false) } } return (
{/* Header */}

Granska kvitto

{/* Content */}
{/* Merchant and total card */}

{receipt.merchant_name || 'Okänd handlare'}

{receipt.receipt_date && (

{formatDate(receipt.receipt_date)}

)}

{formatCurrency(receipt.total_amount || 0, receipt.currency)}

{receipt.vat_amount && (

varav moms {formatCurrency(receipt.vat_amount, receipt.currency)}

)}
{/* Special flags */}
{receipt.is_restaurant && ( Restaurang )} {receipt.is_systembolaget && ( Systembolaget )} {receipt.is_foreign_merchant && ( Utländskt )} {receipt.extraction_confidence && ( 0.8 ? 'outline' : receipt.extraction_confidence > 0.5 ? 'warning' : 'destructive'} className={receipt.extraction_confidence > 0.8 ? 'border-success/50 text-success' : ''} > {Math.round(receipt.extraction_confidence * 100)}% säkerhet {receipt.extraction_confidence <= 0.8 && ' — kontrollera'} )}
{/* Toggle image preview */} {showImage && receipt.image_url && ( Receipt )}
{/* Warning message */} {defaultClassification.warningMessage && (

{defaultClassification.warningMessage}

)} {/* Restaurant representation section */} {receipt.is_restaurant && ( Representation
setRepresentationPersons(parseInt(e.target.value) || undefined)} placeholder="2" />

{representationPersons && receipt.total_amount ? formatCurrency(receipt.total_amount / representationPersons, receipt.currency) : '—'}