'use client' import { useState, useEffect } from 'react' import Link from 'next/link' import { createClient } from '@/lib/supabase/client' import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs' import { PageHeader } from '@/components/ui/page-header' import { EmptyState } from '@/components/ui/empty-state' import { useToast } from '@/components/ui/use-toast' import { formatCurrency } from '@/lib/utils' import { Plus, Search, Wallet, Clock, AlertCircle } from 'lucide-react' import type { SupplierInvoice } from '@/types' type ExpenseInvoice = SupplierInvoice & { supplier?: { id: string; name: string } } const UNPAID_STATUSES = ['registered', 'approved', 'overdue', 'partially_paid'] const PAID_STATUSES = ['paid', 'credited'] function getSimplifiedStatus(status: string): { label: string; variant: 'default' | 'secondary' | 'destructive'; borderColor: string } { switch (status) { case 'registered': case 'approved': return { label: 'Obetald', variant: 'default', borderColor: 'border-l-warning' } case 'overdue': return { label: 'Förfallen', variant: 'destructive', borderColor: 'border-l-destructive' } case 'partially_paid': return { label: 'Delbetald', variant: 'default', borderColor: 'border-l-orange-400' } case 'paid': return { label: 'Betald', variant: 'secondary', borderColor: 'border-l-success' } case 'credited': return { label: 'Krediterad', variant: 'secondary', borderColor: 'border-l-muted-foreground/30' } default: return { label: status, variant: 'secondary', borderColor: 'border-l-muted-foreground/30' } } } function getRelativeTimeLabel(dueDateStr: string, status: string): { text: string; color: string } | null { if (PAID_STATUSES.includes(status)) return null const today = new Date() today.setHours(0, 0, 0, 0) const dueDate = new Date(dueDateStr) dueDate.setHours(0, 0, 0, 0) const diffDays = Math.round((dueDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)) if (diffDays < 0) { return { text: `${Math.abs(diffDays)} dagar försenad`, color: 'text-destructive' } } else if (diffDays === 0) { return { text: 'Förfaller idag', color: 'text-warning-foreground' } } else if (diffDays <= 3) { return { text: `${diffDays} dagar kvar`, color: 'text-warning-foreground' } } else if (diffDays <= 7) { return { text: `${diffDays} dagar kvar`, color: 'text-muted-foreground' } } return null } export default function ExpensesPage() { const [invoices, setInvoices] = useState([]) const [isLoading, setIsLoading] = useState(true) const [searchTerm, setSearchTerm] = useState('') const [activeTab, setActiveTab] = useState('unpaid') const { toast } = useToast() const supabase = createClient() useEffect(() => { fetchExpenses() }, []) async function fetchExpenses() { setIsLoading(true) const { data, error } = await supabase .from('supplier_invoices') .select('*, supplier:suppliers(id, name)') .order('due_date', { ascending: true }) if (error) { toast({ title: 'Fel', description: 'Kunde inte hämta utgifter', variant: 'destructive' }) } else { setInvoices(data || []) } setIsLoading(false) } const filteredInvoices = invoices.filter((inv) => { const matchesSearch = (inv.supplier?.name || '').toLowerCase().includes(searchTerm.toLowerCase()) || inv.supplier_invoice_number.toLowerCase().includes(searchTerm.toLowerCase()) const matchesTab = activeTab === 'unpaid' ? UNPAID_STATUSES.includes(inv.status) : PAID_STATUSES.includes(inv.status) return matchesSearch && matchesTab }) const unpaidInvoices = invoices.filter((i) => UNPAID_STATUSES.includes(i.status)) const overdueInvoices = invoices.filter((i) => i.status === 'overdue') const stats = { unpaidAmount: unpaidInvoices.reduce((sum, i) => sum + i.remaining_amount, 0), unpaidCount: unpaidInvoices.length, overdueAmount: overdueInvoices.reduce((sum, i) => sum + i.remaining_amount, 0), overdueCount: overdueInvoices.length, } return (
} /> {/* Stats */}

Att betala

{formatCurrency(stats.unpaidAmount)}

{stats.unpaidCount} utgifter

0 ? 'text-destructive' : 'text-muted-foreground'}`} />
{stats.overdueCount > 0 ? ( <>

Förfallet

{formatCurrency(stats.overdueAmount)}

{stats.overdueCount} utgifter

) : ( <>

Totalt antal

{invoices.length}

)}
{/* Search and tabs */}
setSearchTerm(e.target.value)} className="pl-10" />
Att betala Betalda
{/* Expense list */} {isLoading ? (
{[1, 2, 3].map((i) => (
))}
) : filteredInvoices.length === 0 ? ( {searchTerm ? (

Inga träffar

Inga utgifter matchar "{searchTerm}"

) : invoices.length === 0 ? ( ) : (

Inga utgifter i denna kategori

Prova att byta flik för att se fler utgifter

)}
) : (
{filteredInvoices.map((inv) => { const status = getSimplifiedStatus(inv.status) const relativeTime = inv.due_date ? getRelativeTimeLabel(inv.due_date, inv.status) : null return (

{inv.supplier?.name || 'Okänd leverantör'}

{status.label}

{inv.supplier_invoice_number} · Förfaller {inv.due_date}

{relativeTime && ( {relativeTime.text} )}

{formatCurrency(inv.total, inv.currency)}

{inv.remaining_amount !== inv.total && inv.remaining_amount > 0 && (

Kvar: {formatCurrency(inv.remaining_amount, inv.currency)}

)}
) })}
)}
) }