"use client"; import { useState } from "react"; import { api } from "~/trpc/react"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { Button } from "~/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "~/components/ui/dialog"; import { toast } from "sonner"; import { useRouter } from "next/navigation"; import { format } from "date-fns"; import { Calendar, FileText, User, DollarSign, Trash2, Edit, Download, Send } from "lucide-react"; import Link from "next/link"; import { generateInvoicePDF } from "~/lib/pdf-export"; interface InvoiceViewProps { invoiceId: string; } const statusColors = { draft: "bg-gray-100 text-gray-800", sent: "bg-blue-100 text-blue-800", paid: "bg-green-100 text-green-800", overdue: "bg-red-100 text-red-800", } as const; const statusLabels = { draft: "Draft", sent: "Sent", paid: "Paid", overdue: "Overdue", } as const; export function InvoiceView({ invoiceId }: InvoiceViewProps) { const router = useRouter(); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [isExportingPDF, setIsExportingPDF] = useState(false); // Fetch invoice data const { data: invoice, isLoading, refetch } = api.invoices.getById.useQuery({ id: invoiceId }); // Delete mutation const deleteInvoice = api.invoices.delete.useMutation({ onSuccess: () => { toast.success("Invoice deleted successfully"); setDeleteDialogOpen(false); router.push("/dashboard/invoices"); }, onError: (error) => { toast.error(error.message ?? "Failed to delete invoice"); }, }); // Update status mutation const updateStatus = api.invoices.updateStatus.useMutation({ onSuccess: () => { toast.success("Status updated successfully"); void refetch(); }, onError: (error) => { toast.error(error.message ?? "Failed to update status"); }, }); const handleDelete = () => { setDeleteDialogOpen(true); }; const confirmDelete = () => { deleteInvoice.mutate({ id: invoiceId }); }; const handleStatusUpdate = (newStatus: "draft" | "sent" | "paid" | "overdue") => { updateStatus.mutate({ id: invoiceId, status: newStatus }); }; const handlePDFExport = async () => { if (!invoice) return; setIsExportingPDF(true); try { await generateInvoicePDF(invoice); toast.success("PDF exported successfully"); } catch (error) { console.error("PDF export error:", error); toast.error("Failed to export PDF. Please try again."); } finally { setIsExportingPDF(false); } }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", }).format(amount); }; const formatDate = (date: Date) => { return format(new Date(date), "MMM dd, yyyy"); }; if (isLoading) { return (
); } if (!invoice) { return (

Invoice not found

The invoice you're looking for doesn't exist or has been deleted.

); } return (
{/* Invoice Header */}
{invoice.invoiceNumber}

Created on {formatDate(invoice.createdAt)}

{statusLabels[invoice.status as keyof typeof statusLabels]}
{/* Invoice Details */}
{/* Main Details */}
{/* Client Information */} Client Information

{invoice.client?.name}

{invoice.client?.email && (

{invoice.client.email}

)} {invoice.client?.phone && (

{invoice.client.phone}

)} {(invoice.client?.addressLine1 || invoice.client?.city || invoice.client?.state) && (

{[ invoice.client?.addressLine1, invoice.client?.addressLine2, invoice.client?.city, invoice.client?.state, invoice.client?.postalCode, ].filter(Boolean).join(", ")}

)}
{/* Invoice Items */} Invoice Items
{invoice.items?.map((item, index) => ( ))}
Date Description Hours Rate Amount
{formatDate(item.date)} {item.description} {item.hours} {formatCurrency(item.rate)} {formatCurrency(item.amount)}
Total: {formatCurrency(invoice.totalAmount)}
{/* Sidebar */}
{/* Invoice Summary */} Invoice Summary

{formatDate(invoice.issueDate)}

{formatDate(invoice.dueDate)}

{statusLabels[invoice.status as keyof typeof statusLabels]}

{formatCurrency(invoice.totalAmount)}

{/* Notes */} {invoice.notes && ( Notes

{invoice.notes}

)} {/* Actions */} Actions
{/* Delete Confirmation Dialog */} Delete Invoice Are you sure you want to delete this invoice? This action cannot be undone.
); }