mirror of
https://github.com/michivonah/nextjs.git
synced 2025-12-22 22:16:28 +01:00
implement form actions for invoices + docs
This commit is contained in:
parent
364f73b06a
commit
39005d46a5
7 changed files with 240 additions and 20 deletions
|
|
@ -0,0 +1,28 @@
|
|||
import Form from '@/app/ui/invoices/edit-form';
|
||||
import Breadcrumbs from '@/app/ui/invoices/breadcrumbs';
|
||||
import { fetchCustomers, fetchInvoiceById } from '@/app/lib/data';
|
||||
|
||||
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(),
|
||||
]);
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
19
dashboard-app-course/app/dashboard/invoices/create/page.tsx
Normal file
19
dashboard-app-course/app/dashboard/invoices/create/page.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
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>
|
||||
);
|
||||
}
|
||||
62
dashboard-app-course/app/lib/actions.ts
Normal file
62
dashboard-app-course/app/lib/actions.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
'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];
|
||||
|
||||
await sql`
|
||||
INSERT INTO invoices (customer_Id, amount, status, date)
|
||||
VALUES (${customerId}, ${amountInCents}, ${status}, ${date})
|
||||
`;
|
||||
|
||||
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;
|
||||
await sql`
|
||||
UPDATE invoices
|
||||
SET customer_id = ${customerId}, amount = ${amountInCents}, status = ${status}
|
||||
WHERE id = ${id}
|
||||
`;
|
||||
|
||||
revalidatePath('/dashboard/invoices');
|
||||
redirect('/dashboard/invoices');
|
||||
}
|
||||
|
||||
export async function deleteInvoice(id: string){
|
||||
await sql`DELETE FROM invoices WHERE id = ${id}`;
|
||||
revalidatePath('/dashboard/invoices');
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { PencilIcon, PlusIcon, TrashIcon } from '@heroicons/react/24/outline';
|
||||
import Link from 'next/link';
|
||||
import { deleteInvoice } from '@/app/lib/actions';
|
||||
|
||||
export function CreateInvoice() {
|
||||
return (
|
||||
|
|
@ -16,7 +17,7 @@ export function CreateInvoice() {
|
|||
export function UpdateInvoice({ id }: { id: string }) {
|
||||
return (
|
||||
<Link
|
||||
href="/dashboard/invoices"
|
||||
href={`/dashboard/invoices/${id}/edit`}
|
||||
className="rounded-md border p-2 hover:bg-gray-100"
|
||||
>
|
||||
<PencilIcon className="w-5" />
|
||||
|
|
@ -25,12 +26,16 @@ export function UpdateInvoice({ id }: { id: string }) {
|
|||
}
|
||||
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ import {
|
|||
UserCircleIcon,
|
||||
} 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 */}
|
||||
<div className="mb-4">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from '@heroicons/react/24/outline';
|
||||
import Link from 'next/link';
|
||||
import { Button } from '@/app/ui/button';
|
||||
import { updateInvoice } from '@/app/lib/actions';
|
||||
|
||||
export default function EditInvoiceForm({
|
||||
invoice,
|
||||
|
|
@ -17,8 +18,9 @@ export default function EditInvoiceForm({
|
|||
invoice: InvoiceForm;
|
||||
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 */}
|
||||
<div className="mb-4">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue