"use client"; import { ArrowLeft, Printer, Loader2, Send } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Select } from "@/components/ui/select"; import { Card, CardContent } from "@/components/ui/card"; import { updateInvoiceStatus, fetchInvoiceDetail, sendInvoiceEmail, getOrgName, type InvoiceRow, } from "@/lib/supabase/invoicing-actions"; import { centsToDecimal, INVOICE_STATUS_LABELS, type InvoiceStatus, type InvoiceWithLineItems, } from "@/lib/supabase/invoicing-types"; import { useState, useEffect, useCallback } from "react"; import SendInvoiceModal from "@/components/invoices/SendInvoiceModal"; function StatusBadge({ status }: { status: InvoiceStatus }) { const styles: Record = { draft: "bg-gray-100 text-gray-600", sent: "bg-blue-100 text-blue-700", paid: "bg-emerald-100 text-emerald-700", overdue: "bg-red-100 text-red-700", cancelled: "bg-gray-100 text-gray-500", }; return ( {INVOICE_STATUS_LABELS[status]} ); } function formatDate(dateStr: string): string { const d = new Date(dateStr + "T00:00:00"); return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric", }); } function DetailLoading() { return (
); } export default function InvoicesDetailView({ initialInvoiceId, onBack, }: { initialInvoiceId: string; onBack: () => void; }) { const [invoice, setInvoice] = useState(null); const [loading, setLoading] = useState(true); const [updating, setUpdating] = useState(false); const [error, setError] = useState(null); const [orgName, setOrgName] = useState(""); const [showSendModal, setShowSendModal] = useState(false); const [sending, setSending] = useState(false); const [sendError, setSendError] = useState(null); useEffect(() => { getOrgName().then(setOrgName).catch(() => {}); }, []); const loadInvoice = useCallback(async (id: string) => { setLoading(true); setError(null); try { const data = await fetchInvoiceDetail(id); setInvoice(data); } catch { setError("Failed to load invoice"); } finally { setLoading(false); } }, []); useEffect(() => { loadInvoice(initialInvoiceId); }, [initialInvoiceId, loadInvoice]); async function handleStatusChange(status: InvoiceStatus) { if (!invoice) return; setUpdating(true); try { const result = await updateInvoiceStatus(invoice.id, status); if (result.success) { setInvoice((prev) => (prev ? { ...prev, status } : prev)); } else { setError(result.error || "Failed to update status"); } } catch { setError("Failed to update status"); } finally { setUpdating(false); } } if (loading) return ; if (error && !invoice) { return (

Invoice Not Found

{error}
); } if (!invoice) return null; const displayTotal = invoice.total_cents > 0 ? `$${centsToDecimal(invoice.total_cents)}` : invoice.amount != null ? `$${invoice.amount.toFixed(2)}` : "$0.00"; const displaySubtotal = invoice.subtotal_cents > 0 ? `$${centsToDecimal(invoice.subtotal_cents)}` : invoice.amount != null ? `$${invoice.amount.toFixed(2)}` : "$0.00"; return (
{/* Header */}

{invoice.invoice_number || "Draft Invoice"}

{invoice.client_name}

{/* Status update */}
{updating && }
{/* Print */} {/* Send to Client */} {invoice.client_email && ( )}
{error && (
{error}
)}
{/* Main Invoice Content */}
{/* Invoice Header */}

Vela

Invoice

{invoice.invoice_number || "Draft"}

Issued: {formatDate(invoice.issue_date)}

Due: {formatDate(invoice.due_date)}

{/* Bill To */}

Bill To

{invoice.client_name}

{invoice.client_email && (

{invoice.client_email}

)} {invoice.client_address && (

{invoice.client_address}

)}
{/* Line Items Table */}
{invoice.line_items.map((item) => ( ))}
Description Qty Unit Price Tax Total
{item.description} {item.quantity} ${centsToDecimal(item.unit_price_cents)} {item.tax_rate}% ${centsToDecimal(item.line_total_cents)}
{/* Totals */}
Subtotal {displaySubtotal}
Tax ${centsToDecimal(invoice.tax_total_cents)}
Total Due {displayTotal} {invoice.currency}
{/* Notes */} {invoice.notes && (

Notes

{invoice.notes}

)}
{/* Sidebar */}

Invoice Summary

Status
Invoice # {invoice.invoice_number || "—"}
Currency {invoice.currency}
Issue Date {formatDate(invoice.issue_date)}
Due Date {formatDate(invoice.due_date)}
Line Items {invoice.line_items.length}

Client

{invoice.client_name}

{invoice.client_email && (

{invoice.client_email}

)} {invoice.client_address && (

{invoice.client_address}

)}

Metadata

Created: {new Date(invoice.created_at).toLocaleString()}

Updated: {new Date(invoice.updated_at).toLocaleString()}

{invoice.created_by && (

Created by: {invoice.created_by}

)}
{/* Print styles */} {/* Send Invoice Modal */} {showSendModal && invoice && ( 0 ? invoice.total_cents / 100 : (invoice.amount || 0)).toFixed(2)}`, }]} orgName={orgName} onClose={() => setShowSendModal(false)} onSuccess={() => { setShowSendModal(false); // Update status to "sent" if (invoice.status === "draft") { handleStatusChange("sent"); } }} /> )}
); }