diff --git a/dashboard/15-final/app/lib/actions.ts b/dashboard/15-final/app/lib/actions.ts index 04e97a39..96ae9acd 100644 --- a/dashboard/15-final/app/lib/actions.ts +++ b/dashboard/15-final/app/lib/actions.ts @@ -5,7 +5,7 @@ import { revalidatePath } from 'next/cache'; import { redirect } from 'next/navigation'; import { z } from 'zod'; -export async function deleteInvoice(id: number) { +export async function deleteInvoice(id: string) { await sql`DELETE FROM invoices WHERE id = ${id}`; revalidatePath('/dashboard/invoices'); } @@ -18,7 +18,6 @@ const NewInvoice = z.object({ const UpdatedInvoice = NewInvoice.extend({ id: z.string(), - date: z.string(), }); export async function createInvoice(formData: FormData) { @@ -37,14 +36,14 @@ export async function createInvoice(formData: FormData) { } export async function updateInvoice(formData: FormData) { - const { id, date, customerId, amount, status } = UpdatedInvoice.parse( + const { id, customerId, amount, status } = UpdatedInvoice.parse( Object.fromEntries(formData.entries()), ); const ammountInCents = amount * 100; await sql` UPDATE invoices - SET customer_id = ${customerId}, amount = ${ammountInCents}, status = ${status}, date = ${date} + SET customer_id = ${customerId}, amount = ${ammountInCents}, status = ${status} WHERE id = ${id} `; diff --git a/dashboard/15-final/app/lib/data.ts b/dashboard/15-final/app/lib/data.ts index a885f9ae..b1e08379 100644 --- a/dashboard/15-final/app/lib/data.ts +++ b/dashboard/15-final/app/lib/data.ts @@ -1,13 +1,8 @@ import { sql } from '@vercel/postgres'; import { formatCurrency } from './utils'; -import { - Revenue, - LatestInvoice, - InvoiceTable, - CustomerTable, -} from './definitions'; - -export async function fetchRevenue(): Promise { +import { Revenue } from './definitions'; + +export async function fetchRevenue() { try { // We artificially delay a reponse for demo purposes. // Don't do this in real life :) @@ -69,7 +64,13 @@ export async function fetchLatestInvoices() { ...invoice, amount: formatCurrency(invoice.amount), })); - return latestInvoices as LatestInvoice[]; + return latestInvoices as { + id: string; + name: string; + image_url: string; + email: string; + amount: string; + }[]; } catch (error) { console.error('Failed to fetch the latest invoices:', error); throw new Error('Failed to fetch the latest invoices.'); @@ -97,7 +98,6 @@ export async function fetchFilteredInvoices( FROM invoices JOIN customers ON invoices.customer_id = customers.id WHERE - invoices.id::text ILIKE ${`%${query}%`} OR customers.name ILIKE ${`%${query}%`} OR customers.email ILIKE ${`%${query}%`} OR invoices.amount::text ILIKE ${`%${query}%`} OR @@ -112,7 +112,6 @@ export async function fetchFilteredInvoices( FROM invoices JOIN customers ON invoices.customer_id = customers.id WHERE - invoices.id::text ILIKE ${`%${query}%`} OR customers.name ILIKE ${`%${query}%`} OR customers.email ILIKE ${`%${query}%`} OR invoices.amount::text ILIKE ${`%${query}%`} OR @@ -126,53 +125,73 @@ export async function fetchFilteredInvoices( // console.log(`Found ${data.rowCount} invoices.`); return { - invoices: data.rows as InvoiceTable[], + invoices: data.rows as { + id: string; + customer_id: string; + customer_name: string; + customer_email: string; + customer_image: string; + date: string; + amount: number; + status: 'pending' | 'paid'; + }[], totalPages, }; } -export async function fetchInvoiceById(id: number) { +export async function fetchInvoiceById(id: string) { const data = await sql` - SELECT - invoices.id, - invoices.amount, - invoices.status, - customers.name - FROM invoices - JOIN customers ON invoices.customer_id = customers.id - WHERE invoices.id = ${id}; -`; - const invoice = data.rows[0]; - return invoice; + SELECT + invoices.id, + invoices.amount, + invoices.status, + customers.name + FROM invoices + JOIN customers ON invoices.customer_id = customers.id + WHERE invoices.id = ${id}; + `; + + const invoice = data.rows.map((invoice) => ({ + ...invoice, + amount: invoice.amount / 100, + })); + + return invoice[0] as { + id: string; + amount: number; + status: string; + name: string; + }; } export async function fetchAllCustomers() { const data = await sql` - SELECT - id, - name - FROM customers - ORDER BY name ASC -`; + SELECT + id, + name + FROM customers + ORDER BY name ASC + `; + const customers = data.rows; - return customers; + return customers as { id: string; name: string }[]; } export async function fetchCustomersTable() { const data = await sql` - SELECT - customers.id, - customers.name, - customers.email, - customers.image_url, - COUNT(invoices.id) AS total_invoices, - SUM(CASE WHEN invoices.status = 'pending' THEN invoices.amount ELSE 0 END) AS total_pending, -- Added a comma here - SUM(CASE WHEN invoices.status = 'paid' THEN invoices.amount ELSE 0 END) AS total_paid -- Fixed by adding comma before this line - FROM customers - LEFT JOIN invoices ON customers.id = invoices.customer_id -- Changed to LEFT JOIN - GROUP BY customers.id, customers.name, customers.email, customers.image_url -- Added GROUP BY - ORDER BY customers.name ASC -`; + SELECT + customers.id, + customers.name, + customers.email, + customers.image_url, + COUNT(invoices.id) AS total_invoices, + SUM(CASE WHEN invoices.status = 'pending' THEN invoices.amount ELSE 0 END) AS total_pending, -- Added a comma here + SUM(CASE WHEN invoices.status = 'paid' THEN invoices.amount ELSE 0 END) AS total_paid -- Fixed by adding comma before this line + FROM customers + LEFT JOIN invoices ON customers.id = invoices.customer_id -- Changed to LEFT JOIN + GROUP BY customers.id, customers.name, customers.email, customers.image_url -- Added GROUP BY + ORDER BY customers.name ASC + `; const customers = data.rows.map((customer) => ({ ...customer, @@ -180,7 +199,13 @@ export async function fetchCustomersTable() { total_paid: formatCurrency(customer.total_paid), })); - console.log('customers', customers); - - return customers as CustomerTable[]; + return customers as { + id: string; + name: string; + email: string; + image_url: string; + total_invoices: number; + total_pending: string; + total_paid: string; + }[]; } diff --git a/dashboard/15-final/app/lib/definitions.ts b/dashboard/15-final/app/lib/definitions.ts index cf8a1264..716a8259 100644 --- a/dashboard/15-final/app/lib/definitions.ts +++ b/dashboard/15-final/app/lib/definitions.ts @@ -20,47 +20,11 @@ export type Invoice = { customer_id: string; amount: number; date: string; - status: 'pending' | 'paid'; -}; - -export type InvoiceTable = { - id: string; - customer_id: string; - customer_name: string; - customer_email: string; - customer_image: string; - date: string; - amount: number; // In TypeScript, this is called a string union type. // It means that the "status" property can only be one of the two strings: 'pending' or 'paid'. status: 'pending' | 'paid'; }; -export type InvoiceForm = { - id: string; - name: string; - amount: number; - status: 'pending' | 'paid'; -}; - -export type LatestInvoice = { - id: string; - name: string; - image_url: string; - email: string; - amount: string; -}; - -export type CustomerTable = { - id: string; - name: string; - email: string; - image_url: string; - total_invoices: number; - total_pending: string; - total_paid: string; -}; - export type Revenue = { month: string; revenue: number; diff --git a/dashboard/15-final/app/ui/customers/table.tsx b/dashboard/15-final/app/ui/customers/table.tsx index 46655e5b..2090efb3 100644 --- a/dashboard/15-final/app/ui/customers/table.tsx +++ b/dashboard/15-final/app/ui/customers/table.tsx @@ -1,8 +1,8 @@ -import { fetchCustomers } from '@/app/lib/data'; +import { fetchCustomersTable } from '@/app/lib/data'; import Image from 'next/image'; export default async function CustomersTable() { - const customers = await fetchCustomers(); + const customers = await fetchCustomersTable(); return (
diff --git a/dashboard/15-final/app/ui/login-form.tsx b/dashboard/15-final/app/ui/login-form.tsx index f39dbe21..ebaec387 100644 --- a/dashboard/15-final/app/ui/login-form.tsx +++ b/dashboard/15-final/app/ui/login-form.tsx @@ -14,7 +14,6 @@ export default function LoginForm() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - console.log(`Email: ${email}, Password: ${password}`); }; return (