From a9249842a5f5a16c3b80f23158403e30fdc20b01 Mon Sep 17 00:00:00 2001 From: Teoto Date: Wed, 29 Apr 2026 09:52:29 +0300 Subject: [PATCH] First Commit --- .env.example | 13 -- app/dashboard/customers/page.tsx | 3 + .../customers/page.tsx:Zone.Identifier | 0 app/dashboard/invoices/page.tsx | 3 + .../invoices/page.tsx:Zone.Identifier | 0 app/dashboard/layout.tsx | 12 ++ app/dashboard/layout.tsx:Zone.Identifier | 0 app/dashboard/page.tsx | 3 + app/dashboard/page.tsx:Zone.Identifier | 0 app/layout.tsx | 7 +- app/layout.tsx:Zone.Identifier | 0 app/lib/data.ts | 64 +++--- app/lib/data.ts:Zone.Identifier | 0 app/lib/definitions.ts | 2 +- app/lib/definitions.ts:Zone.Identifier | 0 app/lib/placeholder-data.js | 188 ++++++++++++++++++ app/lib/placeholder-data.js:Zone.Identifier | 0 app/lib/utils.ts:Zone.Identifier | 0 app/page.tsx | 30 ++- app/page.tsx:Zone.Identifier | 0 app/ui/acme-logo.tsx:Zone.Identifier | 0 app/ui/button.tsx:Zone.Identifier | 0 app/ui/customers/table.tsx | 7 +- app/ui/customers/table.tsx:Zone.Identifier | 0 app/ui/dashboard/cards.tsx | 4 +- app/ui/dashboard/cards.tsx:Zone.Identifier | 0 app/ui/dashboard/latest-invoices.tsx | 4 +- .../latest-invoices.tsx:Zone.Identifier | 0 app/ui/dashboard/nav-links.tsx | 19 +- .../dashboard/nav-links.tsx:Zone.Identifier | 0 app/ui/dashboard/revenue-chart.tsx | 4 +- .../revenue-chart.tsx:Zone.Identifier | 0 app/ui/dashboard/sidenav.tsx | 2 +- app/ui/dashboard/sidenav.tsx:Zone.Identifier | 0 app/ui/fonts.ts | 8 + app/ui/fonts.ts:Zone.Identifier | 0 app/ui/global.css:Zone.Identifier | 0 app/ui/home.module.css | 7 + app/ui/home.module.css:Zone.Identifier | 0 .../invoices/breadcrumbs.tsx:Zone.Identifier | 0 app/ui/invoices/buttons.tsx | 2 +- app/ui/invoices/buttons.tsx:Zone.Identifier | 0 app/ui/invoices/create-form.tsx | 23 ++- .../invoices/create-form.tsx:Zone.Identifier | 0 app/ui/invoices/edit-form.tsx | 21 +- app/ui/invoices/edit-form.tsx:Zone.Identifier | 0 app/ui/invoices/pagination.tsx | 6 +- .../invoices/pagination.tsx:Zone.Identifier | 0 app/ui/invoices/status.tsx:Zone.Identifier | 0 app/ui/invoices/table.tsx:Zone.Identifier | 0 app/ui/login-form.tsx | 12 +- app/ui/login-form.tsx:Zone.Identifier | 0 app/ui/search.tsx:Zone.Identifier | 0 app/ui/skeletons.tsx | 12 +- app/ui/skeletons.tsx:Zone.Identifier | 0 55 files changed, 359 insertions(+), 97 deletions(-) delete mode 100644 .env.example create mode 100644 app/dashboard/customers/page.tsx create mode 100644 app/dashboard/customers/page.tsx:Zone.Identifier create mode 100644 app/dashboard/invoices/page.tsx create mode 100644 app/dashboard/invoices/page.tsx:Zone.Identifier create mode 100644 app/dashboard/layout.tsx create mode 100644 app/dashboard/layout.tsx:Zone.Identifier create mode 100644 app/dashboard/page.tsx create mode 100644 app/dashboard/page.tsx:Zone.Identifier create mode 100644 app/layout.tsx:Zone.Identifier create mode 100644 app/lib/data.ts:Zone.Identifier create mode 100644 app/lib/definitions.ts:Zone.Identifier create mode 100644 app/lib/placeholder-data.js create mode 100644 app/lib/placeholder-data.js:Zone.Identifier create mode 100644 app/lib/utils.ts:Zone.Identifier create mode 100644 app/page.tsx:Zone.Identifier create mode 100644 app/ui/acme-logo.tsx:Zone.Identifier create mode 100644 app/ui/button.tsx:Zone.Identifier create mode 100644 app/ui/customers/table.tsx:Zone.Identifier create mode 100644 app/ui/dashboard/cards.tsx:Zone.Identifier create mode 100644 app/ui/dashboard/latest-invoices.tsx:Zone.Identifier create mode 100644 app/ui/dashboard/nav-links.tsx:Zone.Identifier create mode 100644 app/ui/dashboard/revenue-chart.tsx:Zone.Identifier create mode 100644 app/ui/dashboard/sidenav.tsx:Zone.Identifier create mode 100644 app/ui/fonts.ts create mode 100644 app/ui/fonts.ts:Zone.Identifier create mode 100644 app/ui/global.css:Zone.Identifier create mode 100644 app/ui/home.module.css create mode 100644 app/ui/home.module.css:Zone.Identifier create mode 100644 app/ui/invoices/breadcrumbs.tsx:Zone.Identifier create mode 100644 app/ui/invoices/buttons.tsx:Zone.Identifier create mode 100644 app/ui/invoices/create-form.tsx:Zone.Identifier create mode 100644 app/ui/invoices/edit-form.tsx:Zone.Identifier create mode 100644 app/ui/invoices/pagination.tsx:Zone.Identifier create mode 100644 app/ui/invoices/status.tsx:Zone.Identifier create mode 100644 app/ui/invoices/table.tsx:Zone.Identifier create mode 100644 app/ui/login-form.tsx:Zone.Identifier create mode 100644 app/ui/search.tsx:Zone.Identifier create mode 100644 app/ui/skeletons.tsx:Zone.Identifier diff --git a/.env.example b/.env.example deleted file mode 100644 index 8a85ba7d..00000000 --- a/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# Copy from .env.local on the Vercel dashboard -# https://nextjs.org/learn/dashboard-app/setting-up-your-database#create-a-postgres-database -POSTGRES_URL= -POSTGRES_PRISMA_URL= -POSTGRES_URL_NON_POOLING= -POSTGRES_USER= -POSTGRES_HOST= -POSTGRES_PASSWORD= -POSTGRES_DATABASE= - -# `openssl rand -base64 32` -AUTH_SECRET= -AUTH_URL=http://localhost:3000/api/auth \ No newline at end of file diff --git a/app/dashboard/customers/page.tsx b/app/dashboard/customers/page.tsx new file mode 100644 index 00000000..1adc6ecd --- /dev/null +++ b/app/dashboard/customers/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

Customers Page

; +} \ No newline at end of file diff --git a/app/dashboard/customers/page.tsx:Zone.Identifier b/app/dashboard/customers/page.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/dashboard/invoices/page.tsx b/app/dashboard/invoices/page.tsx new file mode 100644 index 00000000..42451ebd --- /dev/null +++ b/app/dashboard/invoices/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

Invoices Page

; +} \ No newline at end of file diff --git a/app/dashboard/invoices/page.tsx:Zone.Identifier b/app/dashboard/invoices/page.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx new file mode 100644 index 00000000..cea40fe9 --- /dev/null +++ b/app/dashboard/layout.tsx @@ -0,0 +1,12 @@ +import SideNav from '@/app/ui/dashboard/sidenav'; + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( +
+
+ +
+
{children}
+
+ ); +} \ No newline at end of file diff --git a/app/dashboard/layout.tsx:Zone.Identifier b/app/dashboard/layout.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx new file mode 100644 index 00000000..ce2d55a7 --- /dev/null +++ b/app/dashboard/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

Dashboard Page

; +} \ No newline at end of file diff --git a/app/dashboard/page.tsx:Zone.Identifier b/app/dashboard/page.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/layout.tsx b/app/layout.tsx index 225b6038..53f31828 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,3 +1,6 @@ +import '@/app/ui/global.css'; +import { inter } from '@/app/ui/fonts'; + export default function RootLayout({ children, }: { @@ -5,7 +8,7 @@ export default function RootLayout({ }) { return ( - {children} + {children} ); -} +} \ No newline at end of file diff --git a/app/layout.tsx:Zone.Identifier b/app/layout.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/lib/data.ts b/app/lib/data.ts index d9bba040..c25648f6 100644 --- a/app/lib/data.ts +++ b/app/lib/data.ts @@ -1,29 +1,31 @@ -import postgres from 'postgres'; +import { sql } from '@vercel/postgres'; import { CustomerField, - CustomersTableType, + CustomersTable, InvoiceForm, InvoicesTable, LatestInvoiceRaw, + User, Revenue, } from './definitions'; import { formatCurrency } from './utils'; -const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' }); - export async function fetchRevenue() { + // Add noStore() here prevent the response from being cached. + // This is equivalent to in fetch(..., {cache: 'no-store'}). + try { - // Artificially delay a response for demo purposes. - // Don't do this in production :) + // Artificially delay a reponse for demo purposes. + // Don't do this in real life :) // console.log('Fetching revenue data...'); // await new Promise((resolve) => setTimeout(resolve, 3000)); - const data = await sql`SELECT * FROM revenue`; + const data = await sql`SELECT * FROM revenue`; - // console.log('Data fetch completed after 3 seconds.'); + // console.log('Data fetch complete after 3 seconds.'); - return data; + return data.rows; } catch (error) { console.error('Database Error:', error); throw new Error('Failed to fetch revenue data.'); @@ -32,14 +34,14 @@ export async function fetchRevenue() { export async function fetchLatestInvoices() { try { - const data = await sql` + const data = await sql` SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id FROM invoices JOIN customers ON invoices.customer_id = customers.id ORDER BY invoices.date DESC LIMIT 5`; - const latestInvoices = data.map((invoice) => ({ + const latestInvoices = data.rows.map((invoice) => ({ ...invoice, amount: formatCurrency(invoice.amount), })); @@ -68,10 +70,10 @@ export async function fetchCardData() { invoiceStatusPromise, ]); - const numberOfInvoices = Number(data[0][0].count ?? '0'); - const numberOfCustomers = Number(data[1][0].count ?? '0'); - const totalPaidInvoices = formatCurrency(data[2][0].paid ?? '0'); - const totalPendingInvoices = formatCurrency(data[2][0].pending ?? '0'); + const numberOfInvoices = Number(data[0].rows[0].count ?? '0'); + const numberOfCustomers = Number(data[1].rows[0].count ?? '0'); + const totalPaidInvoices = formatCurrency(data[2].rows[0].paid ?? '0'); + const totalPendingInvoices = formatCurrency(data[2].rows[0].pending ?? '0'); return { numberOfCustomers, @@ -81,7 +83,7 @@ export async function fetchCardData() { }; } catch (error) { console.error('Database Error:', error); - throw new Error('Failed to fetch card data.'); + throw new Error('Failed to card data.'); } } @@ -93,7 +95,7 @@ export async function fetchFilteredInvoices( const offset = (currentPage - 1) * ITEMS_PER_PAGE; try { - const invoices = await sql` + const invoices = await sql` SELECT invoices.id, invoices.amount, @@ -114,7 +116,7 @@ export async function fetchFilteredInvoices( LIMIT ${ITEMS_PER_PAGE} OFFSET ${offset} `; - return invoices; + return invoices.rows; } catch (error) { console.error('Database Error:', error); throw new Error('Failed to fetch invoices.'); @@ -123,7 +125,7 @@ export async function fetchFilteredInvoices( export async function fetchInvoicesPages(query: string) { try { - const data = await sql`SELECT COUNT(*) + const count = await sql`SELECT COUNT(*) FROM invoices JOIN customers ON invoices.customer_id = customers.id WHERE @@ -134,7 +136,7 @@ export async function fetchInvoicesPages(query: string) { invoices.status ILIKE ${`%${query}%`} `; - const totalPages = Math.ceil(Number(data[0].count) / ITEMS_PER_PAGE); + const totalPages = Math.ceil(Number(count.rows[0].count) / ITEMS_PER_PAGE); return totalPages; } catch (error) { console.error('Database Error:', error); @@ -144,7 +146,7 @@ export async function fetchInvoicesPages(query: string) { export async function fetchInvoiceById(id: string) { try { - const data = await sql` + const data = await sql` SELECT invoices.id, invoices.customer_id, @@ -154,7 +156,7 @@ export async function fetchInvoiceById(id: string) { WHERE invoices.id = ${id}; `; - const invoice = data.map((invoice) => ({ + const invoice = data.rows.map((invoice) => ({ ...invoice, // Convert amount from cents to dollars amount: invoice.amount / 100, @@ -163,13 +165,12 @@ export async function fetchInvoiceById(id: string) { return invoice[0]; } catch (error) { console.error('Database Error:', error); - throw new Error('Failed to fetch invoice.'); } } export async function fetchCustomers() { try { - const customers = await sql` + const data = await sql` SELECT id, name @@ -177,6 +178,7 @@ export async function fetchCustomers() { ORDER BY name ASC `; + const customers = data.rows; return customers; } catch (err) { console.error('Database Error:', err); @@ -186,7 +188,7 @@ export async function fetchCustomers() { export async function fetchFilteredCustomers(query: string) { try { - const data = await sql` + const data = await sql` SELECT customers.id, customers.name, @@ -204,7 +206,7 @@ export async function fetchFilteredCustomers(query: string) { ORDER BY customers.name ASC `; - const customers = data.map((customer) => ({ + const customers = data.rows.map((customer) => ({ ...customer, total_pending: formatCurrency(customer.total_pending), total_paid: formatCurrency(customer.total_paid), @@ -216,3 +218,13 @@ export async function fetchFilteredCustomers(query: string) { throw new Error('Failed to fetch customer table.'); } } + +export async function getUser(email: string) { + try { + const user = await sql`SELECT * from USERS where email=${email}`; + return user.rows[0] as User; + } catch (error) { + console.error('Failed to fetch user:', error); + throw new Error('Failed to fetch user.'); + } +} diff --git a/app/lib/data.ts:Zone.Identifier b/app/lib/data.ts:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/lib/definitions.ts b/app/lib/definitions.ts index b1a4fbfb..610eb546 100644 --- a/app/lib/definitions.ts +++ b/app/lib/definitions.ts @@ -55,7 +55,7 @@ export type InvoicesTable = { status: 'pending' | 'paid'; }; -export type CustomersTableType = { +export type CustomersTable = { id: string; name: string; email: string; diff --git a/app/lib/definitions.ts:Zone.Identifier b/app/lib/definitions.ts:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/lib/placeholder-data.js b/app/lib/placeholder-data.js new file mode 100644 index 00000000..15a41565 --- /dev/null +++ b/app/lib/placeholder-data.js @@ -0,0 +1,188 @@ +// This file contains placeholder data that you'll be replacing with real data in the Data Fetching chapter: +// https://nextjs.org/learn/dashboard-app/fetching-data +const users = [ + { + id: '410544b2-4001-4271-9855-fec4b6a6442a', + name: 'User', + email: 'user@nextmail.com', + password: '123456', + }, +]; + +const customers = [ + { + id: '3958dc9e-712f-4377-85e9-fec4b6a6442a', + name: 'Delba de Oliveira', + email: 'delba@oliveira.com', + image_url: '/customers/delba-de-oliveira.png', + }, + { + id: '3958dc9e-742f-4377-85e9-fec4b6a6442a', + name: 'Lee Robinson', + email: 'lee@robinson.com', + image_url: '/customers/lee-robinson.png', + }, + { + id: '3958dc9e-737f-4377-85e9-fec4b6a6442a', + name: 'Hector Simpson', + email: 'hector@simpson.com', + image_url: '/customers/hector-simpson.png', + }, + { + id: '50ca3e18-62cd-11ee-8c99-0242ac120002', + name: 'Steven Tey', + email: 'steven@tey.com', + image_url: '/customers/steven-tey.png', + }, + { + id: '3958dc9e-787f-4377-85e9-fec4b6a6442a', + name: 'Steph Dietz', + email: 'steph@dietz.com', + image_url: '/customers/steph-dietz.png', + }, + { + id: '76d65c26-f784-44a2-ac19-586678f7c2f2', + name: 'Michael Novotny', + email: 'michael@novotny.com', + image_url: '/customers/michael-novotny.png', + }, + { + id: 'd6e15727-9fe1-4961-8c5b-ea44a9bd81aa', + name: 'Evil Rabbit', + email: 'evil@rabbit.com', + image_url: '/customers/evil-rabbit.png', + }, + { + id: '126eed9c-c90c-4ef6-a4a8-fcf7408d3c66', + name: 'Emil Kowalski', + email: 'emil@kowalski.com', + image_url: '/customers/emil-kowalski.png', + }, + { + id: 'CC27C14A-0ACF-4F4A-A6C9-D45682C144B9', + name: 'Amy Burns', + email: 'amy@burns.com', + image_url: '/customers/amy-burns.png', + }, + { + id: '13D07535-C59E-4157-A011-F8D2EF4E0CBB', + name: 'Balazs Orban', + email: 'balazs@orban.com', + image_url: '/customers/balazs-orban.png', + }, +]; + +const invoices = [ + { + customer_id: customers[0].id, + amount: 15795, + status: 'pending', + date: '2022-12-06', + }, + { + customer_id: customers[1].id, + amount: 20348, + status: 'pending', + date: '2022-11-14', + }, + { + customer_id: customers[4].id, + amount: 3040, + status: 'paid', + date: '2022-10-29', + }, + { + customer_id: customers[3].id, + amount: 44800, + status: 'paid', + date: '2023-09-10', + }, + { + customer_id: customers[5].id, + amount: 34577, + status: 'pending', + date: '2023-08-05', + }, + { + customer_id: customers[7].id, + amount: 54246, + status: 'pending', + date: '2023-07-16', + }, + { + customer_id: customers[6].id, + amount: 666, + status: 'pending', + date: '2023-06-27', + }, + { + customer_id: customers[3].id, + amount: 32545, + status: 'paid', + date: '2023-06-09', + }, + { + customer_id: customers[4].id, + amount: 1250, + status: 'paid', + date: '2023-06-17', + }, + { + customer_id: customers[5].id, + amount: 8546, + status: 'paid', + date: '2023-06-07', + }, + { + customer_id: customers[1].id, + amount: 500, + status: 'paid', + date: '2023-08-19', + }, + { + customer_id: customers[5].id, + amount: 8945, + status: 'paid', + date: '2023-06-03', + }, + { + customer_id: customers[2].id, + amount: 8945, + status: 'paid', + date: '2023-06-18', + }, + { + customer_id: customers[0].id, + amount: 8945, + status: 'paid', + date: '2023-10-04', + }, + { + customer_id: customers[2].id, + amount: 1000, + status: 'paid', + date: '2022-06-05', + }, +]; + +const revenue = [ + { month: 'Jan', revenue: 2000 }, + { month: 'Feb', revenue: 1800 }, + { month: 'Mar', revenue: 2200 }, + { month: 'Apr', revenue: 2500 }, + { month: 'May', revenue: 2300 }, + { month: 'Jun', revenue: 3200 }, + { month: 'Jul', revenue: 3500 }, + { month: 'Aug', revenue: 3700 }, + { month: 'Sep', revenue: 2500 }, + { month: 'Oct', revenue: 2800 }, + { month: 'Nov', revenue: 3000 }, + { month: 'Dec', revenue: 4800 }, +]; + +module.exports = { + users, + customers, + invoices, + revenue, +}; diff --git a/app/lib/placeholder-data.js:Zone.Identifier b/app/lib/placeholder-data.js:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/lib/utils.ts:Zone.Identifier b/app/lib/utils.ts:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/page.tsx b/app/page.tsx index 8e0184fd..de9ce760 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,16 +1,21 @@ import AcmeLogo from '@/app/ui/acme-logo'; -import { ArrowRightIcon } from '@heroicons/react/24/outline'; +import styles from '@/app/ui/home.module.css'; import Link from 'next/link'; - +import { lusitana } from '@/app/ui/fonts'; +import Image from 'next/image'; export default function Page() { return (
- {/* */} + + {/* */}
diff --git a/app/page.tsx:Zone.Identifier b/app/page.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/acme-logo.tsx:Zone.Identifier b/app/ui/acme-logo.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/button.tsx:Zone.Identifier b/app/ui/button.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/customers/table.tsx b/app/ui/customers/table.tsx index fce2f55d..eaabfd60 100644 --- a/app/ui/customers/table.tsx +++ b/app/ui/customers/table.tsx @@ -1,10 +1,7 @@ import Image from 'next/image'; import { lusitana } from '@/app/ui/fonts'; -import Search from '@/app/ui/search'; -import { - CustomersTableType, - FormattedCustomersTable, -} from '@/app/lib/definitions'; +import Search from '../search'; +import { CustomersTable, FormattedCustomersTable } from '@/app/lib/definitions'; export default async function CustomersTable({ customers, diff --git a/app/ui/customers/table.tsx:Zone.Identifier b/app/ui/customers/table.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/dashboard/cards.tsx b/app/ui/dashboard/cards.tsx index 526e6f97..bbd3a867 100644 --- a/app/ui/dashboard/cards.tsx +++ b/app/ui/dashboard/cards.tsx @@ -13,10 +13,10 @@ const iconMap = { invoices: InboxIcon, }; -export default async function CardWrapper() { +export default async function Cards() { return ( <> - {/* NOTE: Uncomment this code in Chapter 9 */} + {/* NOTE: comment in this code when you get to this point in the course */} {/* diff --git a/app/ui/dashboard/cards.tsx:Zone.Identifier b/app/ui/dashboard/cards.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/dashboard/latest-invoices.tsx b/app/ui/dashboard/latest-invoices.tsx index 27b74f6d..caca7a38 100644 --- a/app/ui/dashboard/latest-invoices.tsx +++ b/app/ui/dashboard/latest-invoices.tsx @@ -9,12 +9,12 @@ export default async function LatestInvoices({ latestInvoices: LatestInvoice[]; }) { return ( -
+

Latest Invoices

- {/* NOTE: Uncomment this code in Chapter 7 */} + {/* NOTE: comment in this code when you get to this point in the course */} {/*
{latestInvoices.map((invoice, i) => { diff --git a/app/ui/dashboard/latest-invoices.tsx:Zone.Identifier b/app/ui/dashboard/latest-invoices.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/dashboard/nav-links.tsx b/app/ui/dashboard/nav-links.tsx index 72fa4626..f048b4d4 100644 --- a/app/ui/dashboard/nav-links.tsx +++ b/app/ui/dashboard/nav-links.tsx @@ -1,8 +1,13 @@ +'use client'; + import { UserGroupIcon, HomeIcon, DocumentDuplicateIcon, } from '@heroicons/react/24/outline'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import clsx from 'clsx'; // Map of links to display in the side navigation. // Depending on the size of the application, this would be stored in a database. @@ -17,19 +22,25 @@ const links = [ ]; export default function NavLinks() { - return ( + const pathname = usePathname(); +return ( <> {links.map((link) => { const LinkIcon = link.icon; return ( -

{link.name}

-
+ ); })} diff --git a/app/ui/dashboard/nav-links.tsx:Zone.Identifier b/app/ui/dashboard/nav-links.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/dashboard/revenue-chart.tsx b/app/ui/dashboard/revenue-chart.tsx index f19e698d..7ccc409a 100644 --- a/app/ui/dashboard/revenue-chart.tsx +++ b/app/ui/dashboard/revenue-chart.tsx @@ -15,7 +15,7 @@ export default async function RevenueChart({ revenue: Revenue[]; }) { const chartHeight = 350; - // NOTE: Uncomment this code in Chapter 7 + // NOTE: comment in this code when you get to this point in the course // const { yAxisLabels, topLabel } = generateYAxis(revenue); @@ -28,7 +28,7 @@ export default async function RevenueChart({

Recent Revenue

- {/* NOTE: Uncomment this code in Chapter 7 */} + {/* NOTE: comment in this code when you get to this point in the course */} {/*
diff --git a/app/ui/dashboard/revenue-chart.tsx:Zone.Identifier b/app/ui/dashboard/revenue-chart.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/dashboard/sidenav.tsx b/app/ui/dashboard/sidenav.tsx index 3d55b46e..006d1ac4 100644 --- a/app/ui/dashboard/sidenav.tsx +++ b/app/ui/dashboard/sidenav.tsx @@ -18,7 +18,7 @@ export default function SideNav() {
- diff --git a/app/ui/dashboard/sidenav.tsx:Zone.Identifier b/app/ui/dashboard/sidenav.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/fonts.ts b/app/ui/fonts.ts new file mode 100644 index 00000000..c9fc10ba --- /dev/null +++ b/app/ui/fonts.ts @@ -0,0 +1,8 @@ +import { Inter, Lusitana } from 'next/font/google'; + +export const inter = Inter({ subsets: ['latin'] }); + +export const lusitana = Lusitana({ + weight: ['400', '700'], + subsets: ['latin'], +}); \ No newline at end of file diff --git a/app/ui/fonts.ts:Zone.Identifier b/app/ui/fonts.ts:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/global.css:Zone.Identifier b/app/ui/global.css:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/home.module.css b/app/ui/home.module.css new file mode 100644 index 00000000..a892477b --- /dev/null +++ b/app/ui/home.module.css @@ -0,0 +1,7 @@ +.shape { + height: 0; + width: 0; + border-bottom: 30px solid black; + border-left: 20px solid transparent; + border-right: 20px solid transparent; +} \ No newline at end of file diff --git a/app/ui/home.module.css:Zone.Identifier b/app/ui/home.module.css:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/invoices/breadcrumbs.tsx:Zone.Identifier b/app/ui/invoices/breadcrumbs.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/invoices/buttons.tsx b/app/ui/invoices/buttons.tsx index 27bff1f7..0edfca3b 100644 --- a/app/ui/invoices/buttons.tsx +++ b/app/ui/invoices/buttons.tsx @@ -27,7 +27,7 @@ export function UpdateInvoice({ id }: { id: string }) { export function DeleteInvoice({ id }: { id: string }) { return ( <> - diff --git a/app/ui/invoices/buttons.tsx:Zone.Identifier b/app/ui/invoices/buttons.tsx:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/app/ui/invoices/create-form.tsx b/app/ui/invoices/create-form.tsx index 35099cef..0aed26f8 100644 --- a/app/ui/invoices/create-form.tsx +++ b/app/ui/invoices/create-form.tsx @@ -1,3 +1,5 @@ +'use client'; + import { CustomerField } from '@/app/lib/definitions'; import Link from 'next/link'; import { @@ -6,7 +8,7 @@ import { CurrencyDollarIcon, UserCircleIcon, } from '@heroicons/react/24/outline'; -import { Button } from '@/app/ui/button'; +import { Button } from '../button'; export default function Form({ customers }: { customers: CustomerField[] }) { return ( @@ -21,7 +23,7 @@ export default function Form({ customers }: { customers: CustomerField[] }) { {/* Customer Name */}