Chapter 11 and 12

This commit is contained in:
Delba de Oliveira
2023-10-26 09:26:45 -07:00
parent 37a3dc3094
commit 55dde02de3
4 changed files with 92 additions and 193 deletions

View File

@@ -9,16 +9,10 @@ import {
UserCircleIcon,
} 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 (
<form action={dispatch}>
<form>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Customer Name */}
<div className="mb-4">
@@ -31,7 +25,6 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
name="customerId"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
defaultValue=""
aria-describedby="customer-error"
>
<option value="" disabled>
Select a customer
@@ -44,18 +37,6 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
</select>
<UserCircleIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500" />
</div>
{state.errors?.customerId ? (
<div
id="customer-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.customerId.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
</div>
{/* Invoice Amount */}
@@ -72,23 +53,11 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
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"
/>
<CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
{state.errors?.amount ? (
<div
id="amount-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.amount.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
s
</div>
{/* Invoice Status */}
@@ -130,24 +99,7 @@ export default function Form({ customers }: { customers: CustomerField[] }) {
</div>
</div>
</div>
{state.errors?.status ? (
<div
aria-describedby="status-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.status.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
</div>
{state.message ? (
<div aria-live="polite" className="my-2 text-sm text-red-500">
<p>{state.message}</p>
</div>
) : null}
</div>
<div className="mt-6 flex justify-end gap-4">
<Link

View File

@@ -9,9 +9,6 @@ import {
} 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({
invoice,
@@ -20,11 +17,8 @@ export default function EditInvoiceForm({
invoice: InvoiceForm;
customers: CustomerField[];
}) {
const initialState = { message: null, errors: [] };
const [state, dispatch] = useFormState(updateInvoice, initialState);
return (
<form action={dispatch}>
<form>
<div className="rounded-md bg-gray-50 p-4 md:p-6">
{/* Invoice ID */}
<input type="hidden" name="id" value={invoice.id} />
@@ -39,7 +33,6 @@ export default function EditInvoiceForm({
name="customerId"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
defaultValue={invoice.customer_id}
aria-describedby="customer-error"
>
<option value="" disabled>
Select a customer
@@ -52,18 +45,6 @@ export default function EditInvoiceForm({
</select>
<UserCircleIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500" />
</div>
{state.errors?.customerId ? (
<div
id="customer-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.customerId.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
</div>
{/* Invoice Amount */}
@@ -80,23 +61,10 @@ export default function EditInvoiceForm({
defaultValue={invoice.amount}
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"
/>
<CurrencyDollarIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
</div>
{state.errors?.amount ? (
<div
id="amount-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.amount.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
</div>
{/* Invoice Status */}
@@ -140,24 +108,7 @@ export default function EditInvoiceForm({
</div>
</div>
</div>
{state.errors?.status ? (
<div
aria-describedby="status-error"
aria-live="polite"
className="mt-2 text-sm text-red-500"
>
{state.errors.status.map((error: string) => (
<p key={error}>{error}</p>
))}
</div>
) : null}
</div>
{state.message ? (
<div aria-live="polite" className="my-2 text-sm text-red-500">
<p>{state.message}</p>
</div>
) : null}
</div>
<div className="mt-6 flex justify-end gap-4">
<Link

View File

@@ -21,7 +21,6 @@
"react-dom": "18.2.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2",
"use-debounce": "^9.0.4",
"zod": "^3.22.2"
},
"devDependencies": {