'use client' import { useState, useEffect, useCallback } 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 { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Camera, Receipt, Check, Clock, AlertCircle, ArrowRight, } from 'lucide-react' import { formatCurrency, formatDate } from '@/lib/utils' import { useRouter } from 'next/navigation' import ReceiptDashboard from '../components/ReceiptDashboard' import ReceiptReviewView from '../components/ReceiptReviewView' import TransactionMatcher from '../components/TransactionMatcher' import type { Receipt as ReceiptType, ReceiptLineItem, ReceiptQueueSummary, ConfirmLineItemInput } from '@/types' type ViewMode = 'dashboard' | 'list' | 'review' | 'match' type ListFilter = 'all' | 'pending' | 'confirmed' export default function ReceiptsPage() { const router = useRouter() const [viewMode, setViewMode] = useState('dashboard') const [listFilter, setListFilter] = useState('all') const [receipts, setReceipts] = useState<(ReceiptType & { line_items: ReceiptLineItem[] })[]>([]) const [summary, setSummary] = useState(null) const [isLoading, setIsLoading] = useState(true) // Selected receipt for review/match const [selectedReceipt, setSelectedReceipt] = useState<(ReceiptType & { line_items: ReceiptLineItem[] }) | null>(null) // Fetch receipts and summary const fetchData = useCallback(async () => { setIsLoading(true) try { const [receiptsRes, queueRes] = await Promise.all([ fetch('/api/extensions/ext/receipt-ocr'), fetch('/api/extensions/ext/receipt-ocr/queue'), ]) const [receiptsData, queueData] = await Promise.all([ receiptsRes.json(), queueRes.json(), ]) if (receiptsData.data) { setReceipts(receiptsData.data) } if (queueData.data?.summary) { setSummary(queueData.data.summary) } } catch (error) { console.error('Fetch error:', error) } finally { setIsLoading(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) // Filter receipts based on tab const filteredReceipts = receipts.filter((r) => { if (listFilter === 'pending') return r.status === 'extracted' if (listFilter === 'confirmed') return r.status === 'confirmed' return true }) // Handle scan receipt const handleScanReceipt = () => { router.push('/receipts/scan') } // Handle view receipt queue const handleViewReceiptQueue = () => { setListFilter('pending') setViewMode('list') } // Handle view transaction queue const handleViewTransactionQueue = () => { router.push('/transactions?filter=unmatched') } // Handle receipt selection for review const handleSelectReceipt = (receipt: ReceiptType & { line_items: ReceiptLineItem[] }) => { setSelectedReceipt(receipt) if (receipt.status === 'extracted') { setViewMode('review') } else { setViewMode('match') } } // Handle confirm receipt const handleConfirmReceipt = async (data: { line_items: ConfirmLineItemInput[] representation_persons?: number representation_purpose?: string }) => { if (!selectedReceipt) return const response = await fetch(`/api/extensions/ext/receipt-ocr/${selectedReceipt.id}/confirm`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (response.ok) { await fetchData() setSelectedReceipt(null) setViewMode('dashboard') } else { const errorData = await response.json() throw new Error(errorData.error || 'Kunde inte bekräfta kvitto') } } // Handle match receipt to transaction const handleMatchReceipt = async (transactionId: string, confidence: number) => { if (!selectedReceipt) return const response = await fetch(`/api/extensions/ext/receipt-ocr/${selectedReceipt.id}/match`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ transaction_id: transactionId, match_confidence: confidence }), }) if (response.ok) { await fetchData() setSelectedReceipt(null) setViewMode('dashboard') } } // Render receipt review view if (viewMode === 'review' && selectedReceipt) { return ( { setSelectedReceipt(null) setViewMode('dashboard') }} onFindMatches={() => setViewMode('match')} /> ) } // Render transaction matcher if (viewMode === 'match' && selectedReceipt) { return ( { setSelectedReceipt(null) setViewMode('dashboard') }} onClose={() => { setSelectedReceipt(null) setViewMode('dashboard') }} /> ) } // Render main page return (

Kvittohantering

{/* Dashboard or List view toggle */} setViewMode(v as ViewMode)} > Översikt Alla kvitton {viewMode === 'dashboard' && ( <> {isLoading ? (
) : summary ? ( ) : (

Kunde inte ladda data

)} )} {viewMode === 'list' && ( <> {/* List filters */}
{/* Receipt list */} {isLoading ? (
{[1, 2, 3].map((i) => ( ))}
) : filteredReceipts.length === 0 ? (

Inga kvitton hittades

) : (
{filteredReceipts.map((receipt) => ( handleSelectReceipt(receipt)} >
{receipt.image_url ? ( Receipt ) : (
)}

{receipt.merchant_name || 'Okänt kvitto'}

{receipt.receipt_date && (

{formatDate(receipt.receipt_date)}

)}
{receipt.status === 'confirmed' && 'Bekräftat'} {receipt.status === 'extracted' && 'Att granska'} {receipt.status === 'processing' && 'Analyserar...'} {receipt.status === 'pending' && 'Väntar'} {receipt.status === 'error' && 'Fel'} {receipt.matched_transaction_id && ( Kopplat )}

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

))}
)} )}
) }