diff --git a/dashboard/final-example/app/ui/invoices/create-form.tsx b/dashboard/final-example/app/ui/invoices/create-form.tsx index 2c234d3..4056179 100644 --- a/dashboard/final-example/app/ui/invoices/create-form.tsx +++ b/dashboard/final-example/app/ui/invoices/create-form.tsx @@ -10,15 +10,10 @@ import { } from '@heroicons/react/24/outline'; import { Button } from '../button'; import { createInvoice } from '@/app/lib/actions'; -// @ts-ignore React types do not yet include useFormState -import { experimental_useFormState as useFormState } from 'react-dom'; export default function Form({ customers }: { customers: CustomerField[] }) { - const initialState = { message: null, errors: [] }; - const [state, dispatch] = useFormState(createInvoice, initialState); - return ( -
+
{/* Customer Name */}
diff --git a/dashboard/final-example/app/ui/invoices/table.tsx b/dashboard/final-example/app/ui/invoices/table.tsx index 0255185..1fa3f8c 100644 --- a/dashboard/final-example/app/ui/invoices/table.tsx +++ b/dashboard/final-example/app/ui/invoices/table.tsx @@ -31,7 +31,6 @@ export default async function InvoicesTable({ className="mr-2 rounded-full" width={28} height={28} - alt={`${invoice.name}'s profile picture`} />

{invoice.name}

@@ -90,7 +89,6 @@ export default async function InvoicesTable({ className="rounded-full" width={28} height={28} - alt={`${invoice.name}'s profile picture`} />

{invoice.name}

diff --git a/dashboard/starter-example/app/dashboard/(overview)/loading.tsx b/dashboard/starter-example/app/dashboard/(overview)/loading.tsx deleted file mode 100644 index ad84532..0000000 --- a/dashboard/starter-example/app/dashboard/(overview)/loading.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import DashboardSkeleton from '@/app/ui/dashboard/skeletons'; - -export default function Loading() { - return ; -} diff --git a/dashboard/starter-example/app/dashboard/(overview)/page.tsx b/dashboard/starter-example/app/dashboard/(overview)/page.tsx deleted file mode 100644 index 5333a38..0000000 --- a/dashboard/starter-example/app/dashboard/(overview)/page.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Cards from '@/app/ui/dashboard/cards'; -import RevenueChart from '@/app/ui/dashboard/revenue-chart'; -import LatestInvoices from '@/app/ui/dashboard/latest-invoices'; -import { lusitana } from '@/app/ui/fonts'; -import { Suspense } from 'react'; -import { - RevenueChartSkeleton, - LatestInvoicesSkeleton, - CardsSkeleton, -} from '@/app/ui/dashboard/skeletons'; - -export default async function Page() { - return ( -
-

- Dashboard -

-
- }> - - -
-
- }> - - - }> - - -
-
- ); -} diff --git a/dashboard/starter-example/app/dashboard/customers/page.tsx b/dashboard/starter-example/app/dashboard/customers/page.tsx deleted file mode 100644 index dcd62af..0000000 --- a/dashboard/starter-example/app/dashboard/customers/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { fetchFilteredCustomers } from '@/app/lib/data'; -import CustomersTable from '@/app/ui/customers/table'; - -export default async function Page({ - searchParams, -}: { - searchParams?: { - query?: string; - page?: string; - }; -}) { - const query = searchParams?.query || ''; - - const customers = await fetchFilteredCustomers(query); - - return ( -
- -
- ); -} diff --git a/dashboard/starter-example/app/dashboard/invoices/[id]/edit/not-found.tsx b/dashboard/starter-example/app/dashboard/invoices/[id]/edit/not-found.tsx deleted file mode 100644 index 444667f..0000000 --- a/dashboard/starter-example/app/dashboard/invoices/[id]/edit/not-found.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import Link from 'next/link'; -import { FaceFrownIcon } from '@heroicons/react/24/outline'; - -export default function NotFound() { - return ( -
- -

404 Not Found

-

Could not find the requested invoice.

- - Go Back - -
- ); -} diff --git a/dashboard/starter-example/app/dashboard/invoices/[id]/edit/page.tsx b/dashboard/starter-example/app/dashboard/invoices/[id]/edit/page.tsx deleted file mode 100644 index 73efa4f..0000000 --- a/dashboard/starter-example/app/dashboard/invoices/[id]/edit/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -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({ params }: { params: { id: string } }) { - const id = params.id; - const [invoice, customers] = await Promise.all([ - fetchInvoiceById(id), - fetchCustomers(), - ]); - - if (!invoice) { - notFound(); - } - - return ( -
- - -
- ); -} diff --git a/dashboard/starter-example/app/dashboard/invoices/create/page.tsx b/dashboard/starter-example/app/dashboard/invoices/create/page.tsx deleted file mode 100644 index 413db57..0000000 --- a/dashboard/starter-example/app/dashboard/invoices/create/page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { fetchCustomers } from '@/app/lib/data'; -import Form from '@/app/ui/invoices/create-form'; -import Breadcrumbs from '@/app/ui/invoices/breadcrumbs'; - -export default async function Page() { - const customers = await fetchCustomers(); - - return ( -
- - -
- ); -} diff --git a/dashboard/starter-example/app/dashboard/invoices/error.tsx b/dashboard/starter-example/app/dashboard/invoices/error.tsx deleted file mode 100644 index 551faa9..0000000 --- a/dashboard/starter-example/app/dashboard/invoices/error.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'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 ( -
-

Something went wrong!

- -
- ); -} diff --git a/dashboard/starter-example/app/dashboard/invoices/page.tsx b/dashboard/starter-example/app/dashboard/invoices/page.tsx deleted file mode 100644 index 1f4dca1..0000000 --- a/dashboard/starter-example/app/dashboard/invoices/page.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import Pagination from '@/app/ui/invoices/pagination'; -import Search from '@/app/ui/search'; -import Table from '@/app/ui/invoices/table'; -import { CreateInvoice } from '@/app/ui/invoices/buttons'; -import { lusitana } from '@/app/ui/fonts'; -import { InvoicesTableSkeleton } from '@/app/ui/dashboard/skeletons'; -import { Suspense } from 'react'; -import { fetchInvoicesPages } from '@/app/lib/data'; - -export default async function Page({ - searchParams, -}: { - searchParams?: { - query?: string; - page?: string; - }; -}) { - const query = searchParams?.query || ''; - const currentPage = Number(searchParams?.page) || 1; - - const totalPages = await fetchInvoicesPages(query); - - return ( -
-
-

Invoices

-
-
- - -
- }> - - -
- -
- - ); -} diff --git a/dashboard/starter-example/app/dashboard/layout.tsx b/dashboard/starter-example/app/dashboard/layout.tsx deleted file mode 100644 index 024d269..0000000 --- a/dashboard/starter-example/app/dashboard/layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import SideNav from '@/app/ui/dashboard/sidenav'; - -export default function Layout({ children }: { children: React.ReactNode }) { - return ( -
-
- -
-
{children}
-
- ); -} diff --git a/dashboard/starter-example/app/lib/actions.ts b/dashboard/starter-example/app/lib/actions.ts deleted file mode 100644 index 08d14f4..0000000 --- a/dashboard/starter-example/app/lib/actions.ts +++ /dev/null @@ -1,121 +0,0 @@ -'use server'; - -import { z } from 'zod'; -import { sql } from '@vercel/postgres'; -import { revalidatePath } from 'next/cache'; -import { redirect } from 'next/navigation'; - -const FormSchema = z.object({ - id: z.string(), - customerId: z.string({ - invalid_type_error: 'Please select a customer.', - }), - amount: z.coerce - .number() - .gt(0, { message: 'Please enter an amount greater than $0.' }), - status: z.enum(['pending', 'paid'], { - invalid_type_error: 'Please select an invoice status.', - }), - date: z.string(), -}); - -const CreateInvoice = FormSchema.omit({ id: true, date: true }); -const UpdateInvoice = FormSchema.omit({ date: true }); -const DeleteInvoice = FormSchema.pick({ id: true }); - -// This is temporary -export type State = { - errors?: { - customerId?: string[]; - amount?: string[]; - status?: string[]; - }; - message: string; -}; - -export async function createInvoice(prevState: State, formData: FormData) { - // Validate form fields using Zod - const validatedFields = CreateInvoice.safeParse({ - customerId: formData.get('customerId'), - amount: formData.get('amount'), - status: formData.get('status'), - }); - - // If form validation fails, return errors early. Otherwise, continue. - if (!validatedFields.success) { - return { - errors: validatedFields.error.flatten().fieldErrors, - message: 'Missing Fields. Failed to Create Invoice.', - }; - } - - // Prepare data for insertion into the database - const { customerId, amount, status } = validatedFields.data; - const amountInCents = amount * 100; - const date = new Date().toISOString().split('T')[0]; - - // Insert data into the database - try { - await sql` - INSERT INTO invoices (customer_id, amount, status, date) - VALUES (${customerId}, ${amountInCents}, ${status}, ${date}) - `; - } catch (error) { - // If a database error occurs, return a more specific error. - return { - message: 'Database Error: Failed to Create Invoice.', - }; - } - - // Revalidate the cache for the invoices page and redirect the user. - revalidatePath('/dashboard/invoices'); - redirect('/dashboard/invoices'); -} - -export async function updateInvoice(prevState: State, formData: FormData) { - const validatedFields = UpdateInvoice.safeParse({ - id: formData.get('id'), - customerId: formData.get('customerId'), - amount: formData.get('amount'), - status: formData.get('status'), - }); - - if (!validatedFields.success) { - return { - errors: validatedFields.error.flatten().fieldErrors, - message: 'Missing Fields. Failed to Update Invoice.', - }; - } - - const { id, customerId, amount, status } = validatedFields.data; - 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(formData: FormData) { - // throw new Error('Failed to Delete Invoice'); - - const { id } = DeleteInvoice.parse({ - id: formData.get('id'), - }); - - try { - await sql`DELETE FROM invoices WHERE id = ${id}`; - revalidatePath('/dashboard/invoices'); - return { message: 'Deleted Invoice' }; - } catch (error) { - return { message: 'Database Error: Failed to Delete Invoice.' }; - } -} diff --git a/dashboard/starter-example/package.json b/dashboard/starter-example/package.json index 849afb4..d1223b8 100644 --- a/dashboard/starter-example/package.json +++ b/dashboard/starter-example/package.json @@ -3,7 +3,6 @@ "scripts": { "build": "next build", "dev": "next dev", - "lint": "next lint", "seed": "node -r dotenv/config ./scripts/seed.js", "start": "next start" },