'use client' import { useState, useEffect } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' import { formatCurrency, formatDate } from '@/lib/utils' import { X, Check, Link2, AlertCircle, Search, Loader2 } from 'lucide-react' import type { Receipt, ReceiptMatchCandidate, Transaction } from '@/types' interface TransactionMatcherProps { receipt: Receipt onMatch: (transactionId: string, confidence: number) => Promise onSkip: () => void onClose: () => void } export default function TransactionMatcher({ receipt, onMatch, onSkip, onClose, }: TransactionMatcherProps) { const [matches, setMatches] = useState([]) const [isLoading, setIsLoading] = useState(true) const [isMatching, setIsMatching] = useState(false) const [selectedMatch, setSelectedMatch] = useState(null) const [error, setError] = useState(null) // Fetch matches on mount useEffect(() => { const fetchMatches = async () => { setIsLoading(true) setError(null) try { const response = await fetch(`/api/extensions/ext/receipt-ocr/${receipt.id}/match`, { method: 'POST', }) const data = await response.json() if (response.ok && data.data?.matches) { setMatches(data.data.matches) } else { setError(data.error || 'Kunde inte hämta matchningar') } } catch { setError('Nätverksfel vid hämtning av matchningar') } finally { setIsLoading(false) } } fetchMatches() }, [receipt.id]) // Handle match confirmation const handleConfirmMatch = async () => { if (!selectedMatch) return const match = matches.find((m) => m.transaction.id === selectedMatch) if (!match) return setIsMatching(true) try { await onMatch(selectedMatch, match.confidence) } catch { setError('Kunde inte koppla kvitto till transaktion') } finally { setIsMatching(false) } } return (
{/* Header */}

Matcha transaktion

{/* Receipt summary */}

{receipt.merchant_name || 'Kvitto'}

{receipt.receipt_date && (

{formatDate(receipt.receipt_date)}

)}

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

{/* Content */}

Möjliga matchningar

{isLoading ? (
{[1, 2, 3].map((i) => ( ))}
) : error ? (

{error}

) : matches.length === 0 ? (

Inga matchande transaktioner hittades

Det finns ingen banktransaktion som matchar detta kvitto

) : (
{matches.map((match) => ( setSelectedMatch(match.transaction.id)} >

{match.transaction.description}

{formatDate(match.transaction.date)}

{formatCurrency(Math.abs(match.transaction.amount), match.transaction.currency)}

0.8 ? 'default' : match.confidence > 0.6 ? 'secondary' : 'outline'} > {Math.round(match.confidence * 100)}% match
{/* Match reasons */}
{match.matchReasons.map((reason, idx) => ( {reason} ))}
{/* Variance info */}
{match.dateVariance > 0 && ( Datum: ±{Math.round(match.dateVariance)} dagar )} {match.amountVariance > 0.01 && ( Belopp: ±{Math.round(match.amountVariance * 100)}% )}
{/* Selected indicator */} {selectedMatch === match.transaction.id && (
)}
))}
)}
{/* Footer actions */}
) }