Index: nextjs-dashboard/app/dashboard/invoices/[id]/edit/not-found.tsx
===================================================================
--- nextjs-dashboard/app/dashboard/invoices/[id]/edit/not-found.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
+++ nextjs-dashboard/app/dashboard/invoices/[id]/edit/not-found.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -0,0 +1,18 @@
+import Link from 'next/link';
+import { FaceFrownIcon } from '@heroicons/react/24/outline';
+
+export default function NotFound() {
+    return (
+        <main className="flex h-full flex-col items-center justify-center gap-2">
+            <FaceFrownIcon className="w-10 text-gray-400" />
+            <h2 className="text-xl font-semibold">404 Not Found</h2>
+            <p>Could not find the requested invoice.</p>
+            <Link
+                href="/dashboard/invoices"
+                className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-400"
+            >
+                Go Back
+            </Link>
+        </main>
+    );
+}
Index: nextjs-dashboard/app/dashboard/invoices/[id]/edit/page.tsx
===================================================================
--- nextjs-dashboard/app/dashboard/invoices/[id]/edit/page.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
+++ nextjs-dashboard/app/dashboard/invoices/[id]/edit/page.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -0,0 +1,33 @@
+import Form from '@/app/ui/invoices/edit-form';
+import Breadcrumbs from '@/app/ui/invoices/breadcrumbs';
+import { fetchInvoiceById, fetchCustomers } from '@/app/lib/data';
+import { notFound } from 'next/navigation';
+
+export default async function Page(props: { params: Promise<{ id: string }> }) {
+    const params = await props.params;
+    const id = params.id;
+    const [invoice, customers] = await Promise.all([
+        fetchInvoiceById(id),
+        fetchCustomers(),
+    ]);
+
+    if (!invoice) {
+        notFound();
+    }
+
+    return (
+        <main>
+            <Breadcrumbs
+                breadcrumbs={[
+                    { label: 'Invoices', href: '/dashboard/invoices' },
+                    {
+                        label: 'Edit Invoice',
+                        href: `/dashboard/invoices/${id}/edit`,
+                        active: true,
+                    },
+                ]}
+            />
+            <Form invoice={invoice} customers={customers} />
+        </main>
+    );
+}
Index: nextjs-dashboard/app/dashboard/invoices/create/page.tsx
===================================================================
--- nextjs-dashboard/app/dashboard/invoices/create/page.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
+++ nextjs-dashboard/app/dashboard/invoices/create/page.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -0,0 +1,23 @@
+import Form from '@/app/ui/invoices/create-form';
+import Breadcrumbs from '@/app/ui/invoices/breadcrumbs';
+import { fetchCustomers } from '@/app/lib/data';
+
+export default async function Page() {
+    const customers = await fetchCustomers();
+
+    return (
+        <main>
+            <Breadcrumbs
+                breadcrumbs={[
+                    { label: 'Invoices', href: '/dashboard/invoices' },
+                    {
+                        label: 'Create Invoice',
+                        href: '/dashboard/invoices/create',
+                        active: true,
+                    },
+                ]}
+            />
+            <Form customers={customers} />
+        </main>
+    );
+}
Index: nextjs-dashboard/app/dashboard/invoices/error.tsx
===================================================================
--- nextjs-dashboard/app/dashboard/invoices/error.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
+++ nextjs-dashboard/app/dashboard/invoices/error.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -0,0 +1,31 @@
+'use client';
+
+import { useEffect } from 'react';
+
+export default function Error({
+    error,
+    reset,
+}: {
+    error: Error & { digest?: string };
+    reset: () => void;
+}) {
+    useEffect(() => {
+        // Optionally log the error to an error reporting service
+        console.error(error);
+    }, [error]);
+
+    return (
+        <main className="flex h-full flex-col items-center justify-center">
+            <h2 className="text-center">Something went wrong!</h2>
+            <button
+                className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-400"
+                onClick={
+                    // Attempt to recover by trying to re-render the invoices route
+                    () => reset()
+                }
+            >
+                Try again
+            </button>
+        </main>
+    );
+}
Index: nextjs-dashboard/app/lib/actions.ts
===================================================================
--- nextjs-dashboard/app/lib/actions.ts	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
+++ nextjs-dashboard/app/lib/actions.ts	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -0,0 +1,75 @@
+'use server'
+
+import { z } from 'zod';
+import { revalidatePath } from 'next/cache';
+import { redirect } from 'next/navigation';
+import postgres from 'postgres';
+
+const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' });
+
+const FormSchema = z.object({
+    id: z.string(),
+    customerId: z.string(),
+    amount: z.coerce.number(),
+    status: z.enum(['pending', 'paid']),
+    date: z.string(),
+});
+
+const CreateInvoice = FormSchema.omit({ id: true, date: true });
+
+export async function createInvoice(formData: FormData) {
+    const { customerId, amount, status } = CreateInvoice.parse({
+        customerId: formData.get('customerId'),
+        amount: formData.get('amount'),
+        status: formData.get('status'),
+    });
+
+    const amountInCents = amount * 100;
+    const date = new Date().toISOString().split('T')[0];
+
+    try {
+        await sql`
+            INSERT INTO invoices (customer_id, amount, status, date)
+            VALUES (${customerId}, ${amountInCents}, ${status}, ${date})
+        `;
+    } catch (error) {
+        return {
+            message: 'Database Error: Failed to Create Invoice.',
+        };
+    }
+
+    revalidatePath('/dashboard/invoices');
+    redirect('/dashboard/invoices');
+}
+
+const UpdateInvoice = FormSchema.omit({ id: true, date: true });
+
+export async function updateInvoice(id: string, formData: FormData) {
+    const { customerId, amount, status } = UpdateInvoice.parse({
+        customerId: formData.get('customerId'),
+        amount: formData.get('amount'),
+        status: formData.get('status'),
+    });
+
+    const amountInCents = amount * 100;
+
+    try {
+        await sql`
+            UPDATE invoices
+            SET customer_id = ${customerId}, amount = ${amountInCents}, status = ${status}
+            WHERE id = ${id}
+        `;
+    } catch (error) {
+        return {
+            message: 'Database Error: Failed to Update Invoice.'
+        };
+    }
+
+    revalidatePath('/dashboard/invoices');
+    redirect('/dashboard/invoices');
+}
+
+export async function deleteInvoice(id: string) {
+    await sql`DELETE FROM invoices WHERE id = ${id}`;
+    revalidatePath('/dashboard/invoices');
+}
Index: nextjs-dashboard/app/ui/invoices/buttons.tsx
===================================================================
--- nextjs-dashboard/app/ui/invoices/buttons.tsx	(revision 1428dc1e1cd66f235e8a718bf6d0868418d5e5cc)
+++ nextjs-dashboard/app/ui/invoices/buttons.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -1,4 +1,5 @@
 import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline';
 import Link from 'next/link';
+import { deleteInvoice } from '@/app/lib/actions';
 
 export function CreateInvoice() {
@@ -17,5 +18,5 @@
   return (
     <Link
-      href="/dashboard/invoices"
+      href={`/dashboard/invoices/${id}/edit`}
       className="rounded-md border p-2 hover:bg-gray-100"
     >
@@ -26,11 +27,13 @@
 
 export function DeleteInvoice({ id }: { id: string }) {
+  const deleteInvoiceWithId = deleteInvoice.bind(null, id);
+
   return (
-    <>
+    <form action={deleteInvoiceWithId}>
       <button type="submit" className="rounded-md border p-2 hover:bg-gray-100">
         <span className="sr-only">Delete</span>
         <TrashIcon className="w-5" />
       </button>
-    </>
+    </form>
   );
 }
Index: nextjs-dashboard/app/ui/invoices/create-form.tsx
===================================================================
--- nextjs-dashboard/app/ui/invoices/create-form.tsx	(revision 1428dc1e1cd66f235e8a718bf6d0868418d5e5cc)
+++ nextjs-dashboard/app/ui/invoices/create-form.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -8,8 +8,9 @@
 } from '@heroicons/react/24/outline';
 import { Button } from '@/app/ui/button';
+import { createInvoice } from '@/app/lib/actions';
 
 export default function Form({ customers }: { customers: CustomerField[] }) {
   return (
-    <form>
+    <form action={createInvoice}>
       <div className="rounded-md bg-gray-50 p-4 md:p-6">
         {/* Customer Name */}
Index: nextjs-dashboard/app/ui/invoices/edit-form.tsx
===================================================================
--- nextjs-dashboard/app/ui/invoices/edit-form.tsx	(revision 1428dc1e1cd66f235e8a718bf6d0868418d5e5cc)
+++ nextjs-dashboard/app/ui/invoices/edit-form.tsx	(revision e1175d1a05c4bd4d0b7496ca469e812995ea2ebc)
@@ -10,4 +10,5 @@
 import Link from 'next/link';
 import { Button } from '@/app/ui/button';
+import { updateInvoice } from '@/app/lib/actions';
 
 export default function EditInvoiceForm({
@@ -18,6 +19,8 @@
   customers: CustomerField[];
 }) {
+  const updateInvoiceWithId = updateInvoice.bind(null, invoice.id);
+
   return (
-    <form>
+    <form action={updateInvoiceWithId}>
       <div className="rounded-md bg-gray-50 p-4 md:p-6">
         {/* Customer Name */}
