diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index 3c03207..0000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-18
diff --git a/dashboard/final-example/.eslintrc.json b/dashboard/final-example/.eslintrc.json
deleted file mode 100644
index bffb357..0000000
--- a/dashboard/final-example/.eslintrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "next/core-web-vitals"
-}
diff --git a/dashboard/final-example/.nvmrc b/dashboard/final-example/.nvmrc
deleted file mode 100644
index 3c03207..0000000
--- a/dashboard/final-example/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-18
diff --git a/dashboard/final-example/app/dashboard/layout.tsx b/dashboard/final-example/app/dashboard/layout.tsx
index 31363d1..8fbc323 100644
--- a/dashboard/final-example/app/dashboard/layout.tsx
+++ b/dashboard/final-example/app/dashboard/layout.tsx
@@ -1,7 +1,5 @@
import SideNav from '@/app/ui/dashboard/sidenav';
-export const experimental_ppr = true;
-
export default function Layout({ children }: { children: React.ReactNode }) {
return (
diff --git a/dashboard/final-example/app/lib/data.ts b/dashboard/final-example/app/lib/data.ts
index c61293d..edb4964 100644
--- a/dashboard/final-example/app/lib/data.ts
+++ b/dashboard/final-example/app/lib/data.ts
@@ -8,12 +8,8 @@ import {
Revenue,
} from './definitions';
import { formatCurrency } from './utils';
-import { unstable_noStore as noStore } from 'next/cache';
export async function fetchRevenue() {
- // Add noStore() here to prevent the response from being cached.
- // This is equivalent to in fetch(..., {cache: 'no-store'}).
- noStore();
try {
// Artificially delay a response for demo purposes.
// Don't do this in production :)
@@ -33,7 +29,6 @@ export async function fetchRevenue() {
}
export async function fetchLatestInvoices() {
- noStore();
try {
const data = await sql`
SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id
@@ -54,7 +49,6 @@ export async function fetchLatestInvoices() {
}
export async function fetchCardData() {
- noStore();
try {
// You can probably combine these into a single SQL query
// However, we are intentionally splitting them to demonstrate
@@ -94,7 +88,6 @@ export async function fetchFilteredInvoices(
query: string,
currentPage: number,
) {
- noStore();
const offset = (currentPage - 1) * ITEMS_PER_PAGE;
try {
@@ -127,7 +120,6 @@ export async function fetchFilteredInvoices(
}
export async function fetchInvoicesPages(query: string) {
- noStore();
try {
const count = await sql`SELECT COUNT(*)
FROM invoices
@@ -149,7 +141,6 @@ export async function fetchInvoicesPages(query: string) {
}
export async function fetchInvoiceById(id: string) {
- noStore();
try {
const data = await sql`
SELECT
@@ -193,7 +184,6 @@ export async function fetchCustomers() {
}
export async function fetchFilteredCustomers(query: string) {
- noStore();
try {
const data = await sql`
SELECT
diff --git a/dashboard/starter-example/app/lib/placeholder-data.js b/dashboard/final-example/app/lib/placeholder-data.ts
similarity index 92%
rename from dashboard/starter-example/app/lib/placeholder-data.js
rename to dashboard/final-example/app/lib/placeholder-data.ts
index dbe5a25..257fb14 100644
--- a/dashboard/starter-example/app/lib/placeholder-data.js
+++ b/dashboard/final-example/app/lib/placeholder-data.ts
@@ -28,12 +28,6 @@ const customers = [
email: 'lee@robinson.com',
image_url: '/customers/lee-robinson.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',
@@ -86,7 +80,7 @@ const invoices = [
date: '2023-08-05',
},
{
- customer_id: customers[7].id,
+ customer_id: customers[2].id,
amount: 54246,
status: 'pending',
date: '2023-07-16',
@@ -150,9 +144,4 @@ const revenue = [
{ month: 'Dec', revenue: 4800 },
];
-module.exports = {
- users,
- customers,
- invoices,
- revenue,
-};
+export { users, customers, invoices, revenue };
diff --git a/dashboard/final-example/app/seed/route.ts b/dashboard/final-example/app/seed/route.ts
new file mode 100644
index 0000000..a38caed
--- /dev/null
+++ b/dashboard/final-example/app/seed/route.ts
@@ -0,0 +1,118 @@
+import bcrypt from 'bcrypt';
+import { db } from '@vercel/postgres';
+import { invoices, customers, revenue, users } from '../lib/placeholder-data';
+
+const client = await db.connect();
+
+async function seedUsers() {
+ await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
+ await client.sql`
+ CREATE TABLE IF NOT EXISTS users (
+ id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email TEXT NOT NULL UNIQUE,
+ password TEXT NOT NULL
+ );
+ `;
+
+ const insertedUsers = await Promise.all(
+ users.map(async (user) => {
+ const hashedPassword = await bcrypt.hash(user.password, 10);
+ return client.sql`
+ INSERT INTO users (id, name, email, password)
+ VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
+ ON CONFLICT (id) DO NOTHING;
+ `;
+ }),
+ );
+
+ return insertedUsers;
+}
+
+async function seedInvoices() {
+ await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
+
+ await client.sql`
+ CREATE TABLE IF NOT EXISTS invoices (
+ id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
+ customer_id UUID NOT NULL,
+ amount INT NOT NULL,
+ status VARCHAR(255) NOT NULL,
+ date DATE NOT NULL
+ );
+ `;
+
+ const insertedInvoices = await Promise.all(
+ invoices.map(
+ (invoice) => client.sql`
+ INSERT INTO invoices (customer_id, amount, status, date)
+ VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
+ ON CONFLICT (id) DO NOTHING;
+ `,
+ ),
+ );
+
+ return insertedInvoices;
+}
+
+async function seedCustomers() {
+ await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
+
+ await client.sql`
+ CREATE TABLE IF NOT EXISTS customers (
+ id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ email VARCHAR(255) NOT NULL,
+ image_url VARCHAR(255) NOT NULL
+ );
+ `;
+
+ const insertedCustomers = await Promise.all(
+ customers.map(
+ (customer) => client.sql`
+ INSERT INTO customers (id, name, email, image_url)
+ VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
+ ON CONFLICT (id) DO NOTHING;
+ `,
+ ),
+ );
+
+ return insertedCustomers;
+}
+
+async function seedRevenue() {
+ await client.sql`
+ CREATE TABLE IF NOT EXISTS revenue (
+ month VARCHAR(4) NOT NULL UNIQUE,
+ revenue INT NOT NULL
+ );
+ `;
+
+ const insertedRevenue = await Promise.all(
+ revenue.map(
+ (rev) => client.sql`
+ INSERT INTO revenue (month, revenue)
+ VALUES (${rev.month}, ${rev.revenue})
+ ON CONFLICT (month) DO NOTHING;
+ `,
+ ),
+ );
+
+ return insertedRevenue;
+}
+
+export async function GET() {
+ try {
+ await client.sql`BEGIN`;
+ await seedUsers();
+ await seedCustomers();
+ await seedInvoices();
+ await seedRevenue();
+ await client.sql`COMMIT`;
+
+ return Response.json({ message: 'Database seeded successfully' });
+ } catch (error) {
+ await client.sql`ROLLBACK`;
+ return Response.json({ error }, { status: 500 });
+ }
+}
diff --git a/dashboard/final-example/app/ui/customers/table.tsx b/dashboard/final-example/app/ui/customers/table.tsx
index fce2f55..9f0399c 100644
--- a/dashboard/final-example/app/ui/customers/table.tsx
+++ b/dashboard/final-example/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 { FormattedCustomersTable } from '@/app/lib/definitions';
export default async function CustomersTable({
customers,
diff --git a/dashboard/final-example/app/ui/dashboard/latest-invoices.tsx b/dashboard/final-example/app/ui/dashboard/latest-invoices.tsx
index 37aab0e..60a8977 100644
--- a/dashboard/final-example/app/ui/dashboard/latest-invoices.tsx
+++ b/dashboard/final-example/app/ui/dashboard/latest-invoices.tsx
@@ -3,6 +3,7 @@ import clsx from 'clsx';
import Image from 'next/image';
import { lusitana } from '@/app/ui/fonts';
import { fetchLatestInvoices } from '@/app/lib/data';
+
export default async function LatestInvoices() {
const latestInvoices = await fetchLatestInvoices();
diff --git a/dashboard/final-example/app/ui/invoices/buttons.tsx b/dashboard/final-example/app/ui/invoices/buttons.tsx
index 79bfac7..ef87e80 100644
--- a/dashboard/final-example/app/ui/invoices/buttons.tsx
+++ b/dashboard/final-example/app/ui/invoices/buttons.tsx
@@ -30,7 +30,7 @@ export function DeleteInvoice({ id }: { id: string }) {
return (