"use client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useParams } from "next/navigation"; import { api } from "@/lib/api"; import type { Invoice } from "@/lib/types"; import { format } from "date-fns"; import { de } from "date-fns/locale"; import { Loader2, AlertTriangle } from "lucide-react"; import { Breadcrumb } from "@/components/layout/Breadcrumb"; const STATUS_BADGE: Record = { draft: "bg-neutral-100 text-neutral-600", sent: "bg-blue-50 text-blue-700", paid: "bg-emerald-50 text-emerald-700", cancelled: "bg-red-50 text-red-600", }; const STATUS_LABEL: Record = { draft: "Entwurf", sent: "Versendet", paid: "Bezahlt", cancelled: "Storniert", }; const TRANSITIONS: Record = { draft: [ { label: "Als versendet markieren", next: "sent" }, { label: "Stornieren", next: "cancelled" }, ], sent: [ { label: "Als bezahlt markieren", next: "paid" }, { label: "Stornieren", next: "cancelled" }, ], paid: [], cancelled: [], }; export default function InvoiceDetailPage() { const { id } = useParams<{ id: string }>(); const queryClient = useQueryClient(); const { data: invoice, isLoading, error } = useQuery({ queryKey: ["invoice", id], queryFn: () => api.get(`/invoices/${id}`), }); const statusMutation = useMutation({ mutationFn: (status: string) => api.patch(`/invoices/${id}/status`, { status }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["invoice", id] }); queryClient.invalidateQueries({ queryKey: ["invoices"] }); }, }); if (isLoading) { return (
); } if (error || !invoice) { return (

Rechnung nicht gefunden.

); } const items = Array.isArray(invoice.items) ? invoice.items : []; const actions = TRANSITIONS[invoice.status] ?? []; return (

{invoice.invoice_number}

{STATUS_LABEL[invoice.status]}

{invoice.client_name}

{actions.map((action) => ( ))}
{/* Invoice details */}
{/* Client info */}

Empfaenger

{invoice.client_name}

{invoice.client_address && (

{invoice.client_address}

)}
{/* Dates */}
{invoice.issued_at && (

Rechnungsdatum

{format(new Date(invoice.issued_at), "d. MMMM yyyy", { locale: de })}

)} {invoice.due_at && (

Faellig am

{format(new Date(invoice.due_at), "d. MMMM yyyy", { locale: de })}

)} {invoice.paid_at && (

Bezahlt am

{format(new Date(invoice.paid_at), "d. MMMM yyyy", { locale: de })}

)}
{/* Line items */}
{items.map((item, i) => ( ))}
Beschreibung Betrag
{item.description} {item.duration_minutes && item.hourly_rate && ( ({Math.floor(item.duration_minutes / 60)}h{" "} {item.duration_minutes % 60}min x {item.hourly_rate} EUR/h) )} {item.amount.toFixed(2)} EUR
{/* Totals */}
Netto {invoice.subtotal.toFixed(2)} EUR
USt. {invoice.tax_rate}% {invoice.tax_amount.toFixed(2)} EUR
Gesamt {invoice.total.toFixed(2)} EUR
{/* Notes */} {invoice.notes && (

Anmerkungen

{invoice.notes}

)}
); }