diff --git a/basics/navigate-between-pages-starter/pages/index.js b/basics/navigate-between-pages-starter/pages/index.js index 32a91df..0647b88 100644 --- a/basics/navigate-between-pages-starter/pages/index.js +++ b/basics/navigate-between-pages-starter/pages/index.js @@ -11,7 +11,7 @@ export default function Home() {

- Welcome to Next.js! + Learn Next.js!

@@ -112,4 +112,4 @@ export default function Home() { `} ) -} \ No newline at end of file +} diff --git a/dashboard/15-final/app/dashboard/customers/page.tsx b/dashboard/15-final/app/dashboard/customers/page.tsx index ff5a46d..cfffe27 100644 --- a/dashboard/15-final/app/dashboard/customers/page.tsx +++ b/dashboard/15-final/app/dashboard/customers/page.tsx @@ -1,3 +1,9 @@ +import CustomersTable from "@/app/ui/customers/table"; + export default function Page() { - return

List of customers
+ return ( +
+ +
+ ) } 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 0d2c74b..9a179ca 100644 --- a/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/[id]/edit/page.tsx @@ -1,3 +1,18 @@ -export default function Page() { - return
Edit Invoice Page
+import InvoiceForm from "@/app/ui/invoices/form"; +import { invoices } from "@/app/lib/dummy-data"; +import { notFound } from "next/navigation"; + +export default function Page({ params }: { params: { id: string } }) { + const id = params.id ? parseInt(params.id) : null; + const invoice = invoices.find((invoice) => invoice.id === id); + + if (!invoice) { + notFound(); + } + + return ( +
+ +
+ ); } diff --git a/dashboard/15-final/app/dashboard/invoices/[id]/page.tsx b/dashboard/15-final/app/dashboard/invoices/[id]/page.tsx deleted file mode 100644 index 188d95c..0000000 --- a/dashboard/15-final/app/dashboard/invoices/[id]/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return
Individual Invoice Page
-} diff --git a/dashboard/15-final/app/dashboard/invoices/create/page.tsx b/dashboard/15-final/app/dashboard/invoices/create/page.tsx index 563cb0c..74a2a0d 100644 --- a/dashboard/15-final/app/dashboard/invoices/create/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/create/page.tsx @@ -1,5 +1,5 @@ -import AddInvoiceForm from "@/app/ui/invoices/add-invoice-form"; +import InvoiceForm from "@/app/ui/invoices/form"; export default function Page() { - return ; + return ; } diff --git a/dashboard/15-final/app/dashboard/invoices/page.tsx b/dashboard/15-final/app/dashboard/invoices/page.tsx index 695f8b6..393ab7d 100644 --- a/dashboard/15-final/app/dashboard/invoices/page.tsx +++ b/dashboard/15-final/app/dashboard/invoices/page.tsx @@ -1,9 +1,9 @@ -import Table from "@/app/ui/invoices/table"; +import InvoicesTable from "@/app/ui/invoices/table"; export default function Page() { return (
- + ); } diff --git a/dashboard/15-final/app/lib/actions.tsx b/dashboard/15-final/app/lib/actions.tsx index efebdd6..92e37c0 100644 --- a/dashboard/15-final/app/lib/actions.tsx +++ b/dashboard/15-final/app/lib/actions.tsx @@ -4,3 +4,8 @@ export async function deleteInvoice(id: number) { // TO DO: Add delete invoice logic console.log("Delete invoice", id); } + +export async function addOrUpdateInvoice(formData: FormData) { + // TO DO: Add create/update invoice logic + console.log("Edit Invoice"); +} diff --git a/dashboard/15-final/app/lib/calculations.tsx b/dashboard/15-final/app/lib/calculations.tsx index 34ab6dc..a31aef9 100644 --- a/dashboard/15-final/app/lib/calculations.tsx +++ b/dashboard/15-final/app/lib/calculations.tsx @@ -1,6 +1,6 @@ import { Invoice, Revenue } from "./definitions"; -export const calculateInvoices = ( +export const calculateAllInvoices = ( invoices: Invoice[], status: "pending" | "paid", ) => { @@ -13,11 +13,34 @@ export const calculateInvoices = ( }); }; +export const calculateCustomerInvoices = ( + invoices: Invoice[], + status: "pending" | "paid", + customerId: number, +) => { + return invoices + .filter((invoice) => invoice.customerId === customerId) + .filter((invoice) => !status || invoice.status === status) + .reduce((total, invoice) => total + invoice.amount / 100, 0) + .toLocaleString("en-US", { + style: "currency", + currency: "USD", + }); +}; + // Once a database is connected, we can use SQL to query the database directly // This will be more efficient than querying all invoices and then filtering them // E.g. "SELECT * FROM invoices // ORDER BY date DESC // LIMIT 5;" + +export const countCustomerInvoices = ( + invoices: Invoice[], + customerId: number, +) => { + return invoices.filter((invoice) => invoice.customerId === customerId).length; +}; + export const findLatestInvoices = (invoices: Invoice[]) => { return [...invoices] .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) diff --git a/dashboard/15-final/app/lib/dummy-data.tsx b/dashboard/15-final/app/lib/dummy-data.tsx index 40b6887..933a940 100644 --- a/dashboard/15-final/app/lib/dummy-data.tsx +++ b/dashboard/15-final/app/lib/dummy-data.tsx @@ -84,6 +84,13 @@ export const invoices: Invoice[] = [ id: 7, customerId: 3, amount: 8945, + status: "pending", + date: "2023-06-01", + }, + { + id: 8, + customerId: 4, + amount: 32545, status: "paid", date: "2023-06-01", }, diff --git a/dashboard/15-final/app/ui/customers/table.tsx b/dashboard/15-final/app/ui/customers/table.tsx new file mode 100644 index 0000000..ceb36ff --- /dev/null +++ b/dashboard/15-final/app/ui/customers/table.tsx @@ -0,0 +1,79 @@ +import { customers, invoices } from "@/app/lib/dummy-data"; +import { + countCustomerInvoices, + calculateCustomerInvoices, +} from "@/app/lib/calculations"; + +export default function CustomersTable() { + return ( +
+
+

Customers

+
+
+
+
+
+ + + + + + + + + + + + {customers.map((customer) => ( + + + + + + + + + ))} + +
+ Profile + + Name + + Email + + Total Invoices + + Total Pending + + Total Paid +
+
+ {customer.name} +
+
+ {customer.name} + + {customer.email} + + {countCustomerInvoices(invoices, customer.id)} + + {calculateCustomerInvoices( + invoices, + "pending", + customer.id, + )} + + {calculateCustomerInvoices(invoices, "paid", customer.id)} +
+
+ + + + ); +} diff --git a/dashboard/15-final/app/ui/dashboard/overview.tsx b/dashboard/15-final/app/ui/dashboard/overview.tsx index 8ff64e0..173005b 100644 --- a/dashboard/15-final/app/ui/dashboard/overview.tsx +++ b/dashboard/15-final/app/ui/dashboard/overview.tsx @@ -1,12 +1,12 @@ import Card from "@/app/ui/dashboard/card"; import { invoices, customers, revenue } from "@/app/lib/dummy-data"; -import { calculateInvoices } from "@/app/lib/calculations"; +import { calculateAllInvoices } from "@/app/lib/calculations"; import RevenueChart from "@/app/ui/dashboard/revenue-chart"; import LatestInvoices from "@/app/ui/dashboard/latest-invoices"; export default function DashboardOverview() { - const totalPaidInvoices = calculateInvoices(invoices, "paid"); - const totalPendingInvoices = calculateInvoices(invoices, "pending"); + const totalPaidInvoices = calculateAllInvoices(invoices, "paid"); + const totalPendingInvoices = calculateAllInvoices(invoices, "pending"); const numberOfInvoices = invoices.length; const numberOfCustomers = customers.length; diff --git a/dashboard/15-final/app/ui/invoices/add-invoice-form.tsx b/dashboard/15-final/app/ui/invoices/form.tsx similarity index 54% rename from dashboard/15-final/app/ui/invoices/add-invoice-form.tsx rename to dashboard/15-final/app/ui/invoices/form.tsx index 65519fd..96295b3 100644 --- a/dashboard/15-final/app/ui/invoices/add-invoice-form.tsx +++ b/dashboard/15-final/app/ui/invoices/form.tsx @@ -1,11 +1,30 @@ "use client"; + import { Invoice } from "@/app/lib/definitions"; import { customers } from "@/app/lib/dummy-data"; import { useState, FormEvent } from "react"; -export default function AddInvoiceForm() { - const [selectedCustomer, setSelectedCustomer] = useState(0); - const [amount, setAmount] = useState(""); +// import { addOrUpdateInvoice } from "@/app/lib/actions"; +// export const dynamic = "force-dynamic"; + +export default function InvoiceForm({ + type, + invoice, +}: { + type: "new" | "edit"; + invoice?: Invoice; +}) { + // TO DO: Replace state and handleSubmit with a Server Action + const customer = customers.find( + (customer) => customer.id === invoice?.customerId, + ); + const initialCustomer = customer ? customer.id : 0; + const initialAmount = invoice?.amount ? invoice.amount / 100 : 0; + const initialStatus = invoice?.status || "pending"; + + const [selectedCustomer, setSelectedCustomer] = useState(initialCustomer); + const [amount, setAmount] = useState(initialAmount); + const [status, setStatus] = useState<"pending" | "paid">(initialStatus); const handleSubmit = (e: FormEvent) => { e.preventDefault(); @@ -13,11 +32,11 @@ export default function AddInvoiceForm() { if (selectedCustomer && amount) { const newInvoice: Invoice = { customerId: selectedCustomer, - amount: parseInt(amount) * 100, // Convert to cents + amount: amount * 100, // Convert to cents // These would be generated on the server id: 1, // Record ID will be automatically incremented - status: "pending", // Default status for a new invoice + status: status, // Default status for a new invoice date: new Date().toISOString().split("T")[0], }; @@ -28,7 +47,9 @@ export default function AddInvoiceForm() { return (
-

New Invoice

+

+ {type === "new" ? "New Invoice" : "Edit Invoice"} +

+ { + const value = e.target.value; + + if (value === "paid" || value === "pending") { + setStatus(value); + } + }} + value={status} + > + + + +
+ ) : null} +
-
+
@@ -71,12 +72,9 @@ export default function Table() { - {/* */} - + {invoices.map((invoice) => ( - {/* */} ))}
Edit - View -
@@ -107,19 +105,14 @@ export default function Table() { {renderInvoiceStatus(invoice.status)} - + - - View, {invoice.id} - -