'use client' import React, { useMemo, useState } from 'react' import PageLayout from '../../components/PageLayout' import { useRouter } from 'next/navigation' import { useVatRates } from './hooks/getTaxes' import { useAdminInvoices } from './hooks/getInvoices' export default function FinanceManagementPage() { const router = useRouter() const { rates, loading: vatLoading, error: vatError } = useVatRates() const [timeframe, setTimeframe] = useState<'7d' | '30d' | '90d' | 'ytd'>('30d') const [billFilter, setBillFilter] = useState({ query: '', status: 'all', from: '', to: '' }) // NEW: fetch invoices from backend const { invoices, loading: invLoading, error: invError, reload, } = useAdminInvoices({ status: billFilter.status !== 'all' ? billFilter.status : undefined, limit: 200, offset: 0, }) // NEW: totals from backend invoices const totals = useMemo(() => { const now = new Date() const inRange = (d: Date) => { const diff = (now.getTime() - d.getTime()) / (1000 * 60 * 60 * 24) if (timeframe === '7d') return diff <= 7 if (timeframe === '30d') return diff <= 30 if (timeframe === '90d') return diff <= 90 return true } const range = invoices.filter(inv => { const dStr = inv.issued_at ?? inv.created_at if (!dStr) return false const d = new Date(dStr) return inRange(d) }) const totalAll = invoices.reduce((s, inv) => s + Number(inv.total_gross ?? 0), 0) const totalRange = range.reduce((s, inv) => s + Number(inv.total_gross ?? 0), 0) return { totalAll, totalRange } }, [invoices, timeframe]) // NEW: filtered rows for table const filteredBills = useMemo(() => { const q = billFilter.query.trim().toLowerCase() const from = billFilter.from ? new Date(billFilter.from) : null const to = billFilter.to ? new Date(billFilter.to) : null return invoices.filter(inv => { const byQuery = !q || String(inv.invoice_number ?? inv.id).toLowerCase().includes(q) || String(inv.buyer_name ?? '').toLowerCase().includes(q) const issued = inv.issued_at ? new Date(inv.issued_at) : (inv.created_at ? new Date(inv.created_at) : null) const byFrom = from ? (issued ? issued >= from : false) : true const byTo = to ? (issued ? issued <= to : false) : true return byQuery && byFrom && byTo }) }, [invoices, billFilter]) const exportBills = (format: 'csv' | 'pdf') => { console.log('[export]', format, { filters: billFilter, invoices: filteredBills }) alert(`Export ${format.toUpperCase()} (dummy) for ${filteredBills.length} invoices`) } return (

Finance Management

Overview of taxes, revenue, and invoices.

{/* Stats */}
Total revenue (all time)
€{totals.totalAll.toFixed(2)}
Revenue (range)
€{totals.totalRange.toFixed(2)}
Invoices (range)
{filteredBills.length}
Timeframe
{/* VAT summary */}

Manage VAT rates

Live data from backend; edit on a separate page.

{vatLoading && 'Loading VAT rates...'} {vatError && {vatError}} {!vatLoading && !vatError && ( <>Active countries: {rates.length} • Examples: {rates.slice(0, 5).map(r => r.country_code).join(', ')} )}
{/* Bills list & filters */}

Invoices

setBillFilter(f => ({ ...f, query: e.target.value }))} className="rounded-lg border border-gray-200 px-3 py-2 focus:ring-2 focus:ring-blue-900 focus:border-transparent" /> setBillFilter(f => ({ ...f, from: e.target.value }))} className="rounded-lg border border-gray-200 px-3 py-2 focus:ring-2 focus:ring-blue-900 focus:border-transparent" /> setBillFilter(f => ({ ...f, to: e.target.value }))} className="rounded-lg border border-gray-200 px-3 py-2 focus:ring-2 focus:ring-blue-900 focus:border-transparent" />
{invError && (
{invError}
)} {invLoading ? ( <> ) : filteredBills.length === 0 ? ( ) : ( filteredBills.map(inv => ( )) )}
Invoice Customer Issued Amount Status Actions
Keine Rechnungen gefunden.
{inv.invoice_number ?? inv.id} {inv.buyer_name ?? '—'} {inv.issued_at ? new Date(inv.issued_at).toLocaleDateString() : '—'} €{Number(inv.total_gross ?? 0).toFixed(2)}{' '} {inv.currency ?? 'EUR'} {inv.status}
) }