From 51872a32775a47e49848c74d94df3abc2d86552a Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Sun, 20 Jul 2025 03:57:33 -0400 Subject: [PATCH] Convert invoice view to client component This conversion enables client-side features like delete functionality with confirmation dialog and live data updates through React Query --- src/app/dashboard/invoices/[id]/view/page.tsx | 105 +++++++++++++++--- .../_components/invoices-data-table.tsx | 4 +- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/app/dashboard/invoices/[id]/view/page.tsx b/src/app/dashboard/invoices/[id]/view/page.tsx index b4e959c..619b0e9 100644 --- a/src/app/dashboard/invoices/[id]/view/page.tsx +++ b/src/app/dashboard/invoices/[id]/view/page.tsx @@ -1,7 +1,9 @@ -import { Suspense } from "react"; -import { notFound } from "next/navigation"; +"use client"; + +import { useState } from "react"; +import { notFound, useRouter, useParams } from "next/navigation"; import Link from "next/link"; -import { api, HydrateClient } from "~/trpc/server"; +import { api } from "~/trpc/react"; import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; import { Button } from "~/components/ui/button"; import { StatusBadge, type StatusType } from "~/components/data/status-badge"; @@ -10,6 +12,15 @@ import { PageHeader } from "~/components/layout/page-header"; import { PDFDownloadButton } from "../_components/pdf-download-button"; import { SendInvoiceButton } from "../_components/send-invoice-button"; import { InvoiceDetailsSkeleton } from "../_components/invoice-details-skeleton"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "~/components/ui/dialog"; +import { toast } from "sonner"; import { Building, @@ -21,14 +32,39 @@ import { User, AlertTriangle, Check, + Trash2, } from "lucide-react"; -interface InvoiceViewPageProps { - params: Promise<{ id: string }>; -} +function InvoiceViewContent({ invoiceId }: { invoiceId: string }) { + const router = useRouter(); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); -async function InvoiceViewContent({ invoiceId }: { invoiceId: string }) { - const invoice = await api.invoices.getById({ id: invoiceId }); + const { data: invoice, isLoading } = api.invoices.getById.useQuery({ + id: invoiceId, + }); + + // Delete mutation + const deleteInvoice = api.invoices.delete.useMutation({ + onSuccess: () => { + toast.success("Invoice deleted successfully"); + router.push("/dashboard/invoices"); + }, + onError: (error) => { + toast.error(error.message ?? "Failed to delete invoice"); + }, + }); + + const handleDelete = () => { + setDeleteDialogOpen(true); + }; + + const confirmDelete = () => { + deleteInvoice.mutate({ id: invoiceId }); + }; + + if (isLoading) { + return ; + } if (!invoice) { notFound(); @@ -368,22 +404,57 @@ async function InvoiceViewContent({ invoiceId }: { invoiceId: string }) { {invoice.status === "draft" && ( )} + + + + {/* Delete Confirmation Dialog */} + + + + Delete Invoice + + Are you sure you want to delete invoice{" "} + {invoice.invoiceNumber}? This action cannot be + undone and will permanently remove the invoice and all its data. + + + + + + + + ); } -export default async function InvoiceViewPage({ params }: InvoiceViewPageProps) { - const { id } = await params; +export default function InvoiceViewPage() { + const params = useParams(); + const id = params.id as string; - return ( - - }> - - - - ); + return ; } diff --git a/src/app/dashboard/invoices/_components/invoices-data-table.tsx b/src/app/dashboard/invoices/_components/invoices-data-table.tsx index fe633ae..93679ad 100644 --- a/src/app/dashboard/invoices/_components/invoices-data-table.tsx +++ b/src/app/dashboard/invoices/_components/invoices-data-table.tsx @@ -109,7 +109,7 @@ export function InvoicesDataTable({ invoices }: InvoicesDataTableProps) { }); const handleRowClick = (invoice: Invoice) => { - router.push(`/dashboard/invoices/${invoice.id}`); + router.push(`/dashboard/invoices/${invoice.id}/view`); }; const handleDelete = (invoice: Invoice) => { @@ -208,7 +208,7 @@ export function InvoicesDataTable({ invoices }: InvoicesDataTableProps) { const invoice = row.original; return (
- +