From 24ac91ac030769fa8d090970661f886e73de6882 Mon Sep 17 00:00:00 2001 From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Date: Thu, 12 Oct 2023 14:54:02 +0100 Subject: [PATCH] Fix form bugs (#209) * Move breadcrumbs * Update definitions * Update breadcrumbs.tsx * Move redirect outside try/catch block * Update forms --- .../app/dashboard/invoices/[id]/edit/page.tsx | 8 +++---- .../app/dashboard/invoices/create/page.tsx | 6 ++--- dashboard/15-final/app/lib/actions.ts | 13 +++++----- dashboard/15-final/app/lib/data.ts | 17 +++++++------ dashboard/15-final/app/lib/definitions.ts | 4 ++-- .../15-final/app/ui/invoices/create-form.tsx | 19 ++++++--------- .../15-final/app/ui/invoices/edit-form.tsx | 24 +++++++++---------- 7 files changed, 42 insertions(+), 49 deletions(-) diff --git a/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx b/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx index 3529961..d9a5750 100644 --- a/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx @@ -1,12 +1,12 @@ -import { fetchInvoiceById, fetchCustomerNames } from '@/app/lib/data'; -import { notFound } from 'next/navigation'; 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 = await fetchInvoiceById(id); - const customerNames = await fetchCustomerNames(); + const customers = await fetchCustomers(); if (!invoice) { notFound(); @@ -24,7 +24,7 @@ export default async function Page({ params }: { params: { id: string } }) { }, ]} /> -
+ ); } diff --git a/dashboard/15-final/app/dashboard/invoices/create/page.tsx b/dashboard/15-final/app/dashboard/invoices/create/page.tsx index 3d036cc..413db57 100644 --- a/dashboard/15-final/app/dashboard/invoices/create/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/create/page.tsx @@ -1,9 +1,9 @@ -import { fetchCustomerNames } from '@/app/lib/data'; +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 customerNames = await fetchCustomerNames(); + const customers = await fetchCustomers(); return (
@@ -17,7 +17,7 @@ export default async function Page() { }, ]} /> - +
); } diff --git a/dashboard/15-final/app/lib/actions.ts b/dashboard/15-final/app/lib/actions.ts index 06d67c7..5496177 100644 --- a/dashboard/15-final/app/lib/actions.ts +++ b/dashboard/15-final/app/lib/actions.ts @@ -58,15 +58,16 @@ export async function createInvoice(prevState: State, formData: FormData) { INSERT INTO invoices (customer_id, amount, status, date) VALUES (${customerId}, ${amountInCents}, ${status}, ${date}) `; - - revalidatePath('/dashboard/invoices'); - redirect('/dashboard/invoices'); } catch (error) { // If a database error occurs, return a more specific error. return { message: 'Database error: Failed to create invoice.', }; } + + // Revalidate cache and redirect user to invoices page + revalidatePath('/dashboard/invoices'); + redirect('/dashboard/invoices'); } export async function updateInvoice(prevState: State, formData: FormData) { @@ -93,12 +94,12 @@ export async function updateInvoice(prevState: State, formData: FormData) { SET customer_id = ${customerId}, amount = ${amountInCents}, status = ${status} WHERE id = ${id} `; - - revalidatePath('/dashboard/invoices'); - redirect('/dashboard/invoices'); } catch (error) { return { message: 'Database error: Failed to update invoice.' }; } + + revalidatePath('/dashboard/invoices'); + redirect('/dashboard/invoices'); } export async function deleteInvoice(formData: FormData) { diff --git a/dashboard/15-final/app/lib/data.ts b/dashboard/15-final/app/lib/data.ts index b5e75d5..e0ec01d 100644 --- a/dashboard/15-final/app/lib/data.ts +++ b/dashboard/15-final/app/lib/data.ts @@ -1,13 +1,13 @@ import { sql } from '@vercel/postgres'; -import { formatCurrency } from './utils'; import { - Revenue, - InvoicesTable, + CustomerField, CustomersTable, InvoiceForm, - CustomerName, + InvoicesTable, LatestInvoiceRaw, + Revenue, } from './definitions'; +import { formatCurrency } from './utils'; export async function fetchRevenue() { try { @@ -141,11 +141,10 @@ export async function fetchInvoiceById(id: string) { const data = await sql` SELECT invoices.id, + invoices.customer_id, invoices.amount, - invoices.status, - customers.name + invoices.status FROM invoices - JOIN customers ON invoices.customer_id = customers.id WHERE invoices.id = ${id}; `; @@ -162,9 +161,9 @@ export async function fetchInvoiceById(id: string) { } } -export async function fetchCustomerNames() { +export async function fetchCustomers() { try { - const data = await sql` + const data = await sql` SELECT id, name diff --git a/dashboard/15-final/app/lib/definitions.ts b/dashboard/15-final/app/lib/definitions.ts index 0d609f2..6c6aa63 100644 --- a/dashboard/15-final/app/lib/definitions.ts +++ b/dashboard/15-final/app/lib/definitions.ts @@ -75,14 +75,14 @@ export type FormattedCustomersTable = { total_paid: string; }; -export type CustomerName = { +export type CustomerField = { id: string; name: string; }; export type InvoiceForm = { id: string; - name: string; + customer_id: string; amount: number; status: 'pending' | 'paid'; }; diff --git a/dashboard/15-final/app/ui/invoices/create-form.tsx b/dashboard/15-final/app/ui/invoices/create-form.tsx index 82b547f..a24c888 100644 --- a/dashboard/15-final/app/ui/invoices/create-form.tsx +++ b/dashboard/15-final/app/ui/invoices/create-form.tsx @@ -1,6 +1,6 @@ 'use client'; -import { CustomerName } from '@/app/lib/definitions'; +import { CustomerField } from '@/app/lib/definitions'; import Link from 'next/link'; import { CheckIcon, @@ -13,11 +13,7 @@ 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({ - customerNames, -}: { - customerNames: CustomerName[]; -}) { +export default function Form({ customers }: { customers: CustomerField[] }) { const initialState = { message: null, errors: [] }; const [state, dispatch] = useFormState(createInvoice, initialState); @@ -40,9 +36,9 @@ export default function Form({ - {customerNames.map((name) => ( - ))} @@ -73,12 +69,11 @@ export default function Form({ id="amount" name="amount" type="number" + step="0.01" placeholder="Enter USD amount" className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500" aria-describedby="amount-error" - style={ - { '-moz-appearance': 'textfield' } as React.CSSProperties - } + style={{ MozAppearance: 'textfield' } as React.CSSProperties} /> diff --git a/dashboard/15-final/app/ui/invoices/edit-form.tsx b/dashboard/15-final/app/ui/invoices/edit-form.tsx index 6f28c9b..685d3b7 100644 --- a/dashboard/15-final/app/ui/invoices/edit-form.tsx +++ b/dashboard/15-final/app/ui/invoices/edit-form.tsx @@ -1,26 +1,24 @@ 'use client'; -import { CustomerName, InvoiceForm } from '@/app/lib/definitions'; -import Link from 'next/link'; +import { CustomerField, InvoiceForm } from '@/app/lib/definitions'; import { CheckIcon, ClockIcon, CurrencyDollarIcon, UserCircleIcon, } from '@heroicons/react/24/outline'; +import Link from 'next/link'; import { Button } from '../button'; import { updateInvoice } from '@/app/lib/actions'; // @ts-ignore React types do not yet include useFormState import { experimental_useFormState as useFormState } from 'react-dom'; export default function EditInvoiceForm({ - id, invoice, - customerNames, + customers, }: { - id: string; invoice: InvoiceForm; - customerNames: CustomerName[]; + customers: CustomerField[]; }) { const initialState = { message: null, errors: [] }; const [state, dispatch] = useFormState(updateInvoice, initialState); @@ -28,6 +26,8 @@ export default function EditInvoiceForm({ return (
+ {/* Invoice ID */} + {/* Customer Name */}