Skip to content

Commit 5a5ade6

Browse files
authored
Merge pull request #2 from progaurab/nextjs-dashboard-chap8
nextjs-dashboard-chat8
2 parents c9fb1fa + b45e2cb commit 5a5ade6

File tree

7 files changed

+189
-166
lines changed

7 files changed

+189
-166
lines changed

.env.example

-13
This file was deleted.

app/dashboard/page.tsx

+39-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,39 @@
1-
export default function Page() {
2-
return <p>Dashboard Page</p>;
3-
}
1+
import { Card } from '@/app/ui/dashboard/cards';
2+
import RevenueChart from '@/app/ui/dashboard/revenue-chart';
3+
import LatestInvoices from '@/app/ui/dashboard/latest-invoices';
4+
import { lusitana } from '@/app/ui/fonts';
5+
import { fetchRevenue, fetchLatestInvoices, fetchCardData } from '@/app/lib/data';
6+
7+
8+
export default async function Page() {
9+
const revenue = await fetchRevenue();
10+
const latestInvoices = await fetchLatestInvoices();
11+
const {
12+
numberOfInvoices,
13+
numberOfCustomers,
14+
totalPaidInvoices,
15+
totalPendingInvoices,
16+
} = await fetchCardData();
17+
18+
return (
19+
<main>
20+
<h1 className={`${lusitana.className} mb-4 text-xl md:text-2xl`}>
21+
Dashboard
22+
</h1>
23+
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
24+
<Card title="Collected" value={totalPaidInvoices} type="collected" />
25+
<Card title="Pending" value={totalPendingInvoices} type="pending" />
26+
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
27+
<Card
28+
title="Total Customers"
29+
value={numberOfCustomers}
30+
type="customers"
31+
/>
32+
</div>
33+
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
34+
<RevenueChart revenue={revenue} />
35+
<LatestInvoices latestInvoices={latestInvoices} />
36+
</div>
37+
</main>
38+
);
39+
}

app/lib/data.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ export async function fetchRevenue() {
1414
// Artificially delay a response for demo purposes.
1515
// Don't do this in production :)
1616

17-
// console.log('Fetching revenue data...');
18-
// await new Promise((resolve) => setTimeout(resolve, 3000));
17+
console.log('Fetching revenue data...');
18+
await new Promise((resolve) => setTimeout(resolve, 3000));
1919

2020
const data = await sql<Revenue>`SELECT * FROM revenue`;
2121

22-
// console.log('Data fetch completed after 3 seconds.');
22+
console.log('Data fetch completed after 3 seconds.');
2323

2424
return data.rows;
2525
} catch (error) {

app/query/route.ts

+20-20
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
// import { db } from "@vercel/postgres";
1+
import { db } from "@vercel/postgres";
22

3-
// const client = await db.connect();
3+
const client = await db.connect();
44

5-
// async function listInvoices() {
6-
// const data = await client.sql`
7-
// SELECT invoices.amount, customers.name
8-
// FROM invoices
9-
// JOIN customers ON invoices.customer_id = customers.id
10-
// WHERE invoices.amount = 666;
11-
// `;
5+
async function listInvoices() {
6+
const data = await client.sql`
7+
SELECT invoices.amount, customers.name
8+
FROM invoices
9+
JOIN customers ON invoices.customer_id = customers.id
10+
WHERE invoices.amount = 666;
11+
`;
1212

13-
// return data.rows;
14-
// }
13+
return data.rows;
14+
}
1515

1616
export async function GET() {
17-
return Response.json({
18-
message:
19-
'Uncomment this file and remove this line. You can delete this file when you are finished.',
20-
});
21-
// try {
22-
// return Response.json(await listInvoices());
23-
// } catch (error) {
24-
// return Response.json({ error }, { status: 500 });
25-
// }
17+
// return Response.json({
18+
// message:
19+
// 'Uncomment this file and remove this line. You can delete this file when you are finished.',
20+
// });
21+
try {
22+
return Response.json(await listInvoices());
23+
} catch (error) {
24+
return Response.json({ error }, { status: 500 });
25+
}
2626
}

app/seed/route.ts

+119-119
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,122 @@
1-
// import bcrypt from 'bcrypt';
2-
// import { db } from '@vercel/postgres';
3-
// import { invoices, customers, revenue, users } from '../lib/placeholder-data';
4-
5-
// const client = await db.connect();
6-
7-
// async function seedUsers() {
8-
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
9-
// await client.sql`
10-
// CREATE TABLE IF NOT EXISTS users (
11-
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
12-
// name VARCHAR(255) NOT NULL,
13-
// email TEXT NOT NULL UNIQUE,
14-
// password TEXT NOT NULL
15-
// );
16-
// `;
17-
18-
// const insertedUsers = await Promise.all(
19-
// users.map(async (user) => {
20-
// const hashedPassword = await bcrypt.hash(user.password, 10);
21-
// return client.sql`
22-
// INSERT INTO users (id, name, email, password)
23-
// VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
24-
// ON CONFLICT (id) DO NOTHING;
25-
// `;
26-
// }),
27-
// );
28-
29-
// return insertedUsers;
30-
// }
31-
32-
// async function seedInvoices() {
33-
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
34-
35-
// await client.sql`
36-
// CREATE TABLE IF NOT EXISTS invoices (
37-
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
38-
// customer_id UUID NOT NULL,
39-
// amount INT NOT NULL,
40-
// status VARCHAR(255) NOT NULL,
41-
// date DATE NOT NULL
42-
// );
43-
// `;
44-
45-
// const insertedInvoices = await Promise.all(
46-
// invoices.map(
47-
// (invoice) => client.sql`
48-
// INSERT INTO invoices (customer_id, amount, status, date)
49-
// VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
50-
// ON CONFLICT (id) DO NOTHING;
51-
// `,
52-
// ),
53-
// );
54-
55-
// return insertedInvoices;
56-
// }
57-
58-
// async function seedCustomers() {
59-
// await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
60-
61-
// await client.sql`
62-
// CREATE TABLE IF NOT EXISTS customers (
63-
// id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
64-
// name VARCHAR(255) NOT NULL,
65-
// email VARCHAR(255) NOT NULL,
66-
// image_url VARCHAR(255) NOT NULL
67-
// );
68-
// `;
69-
70-
// const insertedCustomers = await Promise.all(
71-
// customers.map(
72-
// (customer) => client.sql`
73-
// INSERT INTO customers (id, name, email, image_url)
74-
// VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
75-
// ON CONFLICT (id) DO NOTHING;
76-
// `,
77-
// ),
78-
// );
79-
80-
// return insertedCustomers;
81-
// }
82-
83-
// async function seedRevenue() {
84-
// await client.sql`
85-
// CREATE TABLE IF NOT EXISTS revenue (
86-
// month VARCHAR(4) NOT NULL UNIQUE,
87-
// revenue INT NOT NULL
88-
// );
89-
// `;
90-
91-
// const insertedRevenue = await Promise.all(
92-
// revenue.map(
93-
// (rev) => client.sql`
94-
// INSERT INTO revenue (month, revenue)
95-
// VALUES (${rev.month}, ${rev.revenue})
96-
// ON CONFLICT (month) DO NOTHING;
97-
// `,
98-
// ),
99-
// );
100-
101-
// return insertedRevenue;
102-
// }
1+
import bcrypt from 'bcrypt';
2+
import { db } from '@vercel/postgres';
3+
import { invoices, customers, revenue, users } from '../lib/placeholder-data';
4+
5+
const client = await db.connect();
6+
7+
async function seedUsers() {
8+
await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
9+
await client.sql`
10+
CREATE TABLE IF NOT EXISTS users (
11+
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
12+
name VARCHAR(255) NOT NULL,
13+
email TEXT NOT NULL UNIQUE,
14+
password TEXT NOT NULL
15+
);
16+
`;
17+
18+
const insertedUsers = await Promise.all(
19+
users.map(async (user) => {
20+
const hashedPassword = await bcrypt.hash(user.password, 10);
21+
return client.sql`
22+
INSERT INTO users (id, name, email, password)
23+
VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
24+
ON CONFLICT (id) DO NOTHING;
25+
`;
26+
}),
27+
);
28+
29+
return insertedUsers;
30+
}
31+
32+
async function seedInvoices() {
33+
await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
34+
35+
await client.sql`
36+
CREATE TABLE IF NOT EXISTS invoices (
37+
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
38+
customer_id UUID NOT NULL,
39+
amount INT NOT NULL,
40+
status VARCHAR(255) NOT NULL,
41+
date DATE NOT NULL
42+
);
43+
`;
44+
45+
const insertedInvoices = await Promise.all(
46+
invoices.map(
47+
(invoice) => client.sql`
48+
INSERT INTO invoices (customer_id, amount, status, date)
49+
VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
50+
ON CONFLICT (id) DO NOTHING;
51+
`,
52+
),
53+
);
54+
55+
return insertedInvoices;
56+
}
57+
58+
async function seedCustomers() {
59+
await client.sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
60+
61+
await client.sql`
62+
CREATE TABLE IF NOT EXISTS customers (
63+
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
64+
name VARCHAR(255) NOT NULL,
65+
email VARCHAR(255) NOT NULL,
66+
image_url VARCHAR(255) NOT NULL
67+
);
68+
`;
69+
70+
const insertedCustomers = await Promise.all(
71+
customers.map(
72+
(customer) => client.sql`
73+
INSERT INTO customers (id, name, email, image_url)
74+
VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
75+
ON CONFLICT (id) DO NOTHING;
76+
`,
77+
),
78+
);
79+
80+
return insertedCustomers;
81+
}
82+
83+
async function seedRevenue() {
84+
await client.sql`
85+
CREATE TABLE IF NOT EXISTS revenue (
86+
month VARCHAR(4) NOT NULL UNIQUE,
87+
revenue INT NOT NULL
88+
);
89+
`;
90+
91+
const insertedRevenue = await Promise.all(
92+
revenue.map(
93+
(rev) => client.sql`
94+
INSERT INTO revenue (month, revenue)
95+
VALUES (${rev.month}, ${rev.revenue})
96+
ON CONFLICT (month) DO NOTHING;
97+
`,
98+
),
99+
);
100+
101+
return insertedRevenue;
102+
}
103103

104104
export async function GET() {
105-
return Response.json({
106-
message:
107-
'Uncomment this file and remove this line. You can delete this file when you are finished.',
108-
});
109-
// try {
110-
// await client.sql`BEGIN`;
111-
// await seedUsers();
112-
// await seedCustomers();
113-
// await seedInvoices();
114-
// await seedRevenue();
115-
// await client.sql`COMMIT`;
116-
117-
// return Response.json({ message: 'Database seeded successfully' });
118-
// } catch (error) {
119-
// await client.sql`ROLLBACK`;
120-
// return Response.json({ error }, { status: 500 });
121-
// }
105+
// return Response.json({
106+
// message:
107+
// 'Uncomment this file and remove this line. You can delete this file when you are finished.',
108+
// });
109+
try {
110+
await client.sql`BEGIN`;
111+
await seedUsers();
112+
await seedCustomers();
113+
await seedInvoices();
114+
await seedRevenue();
115+
await client.sql`COMMIT`;
116+
117+
return Response.json({ message: 'Database seeded successfully' });
118+
} catch (error) {
119+
await client.sql`ROLLBACK`;
120+
return Response.json({ error }, { status: 500 });
121+
}
122122
}

app/ui/dashboard/latest-invoices.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default async function LatestInvoices({
1616
<div className="flex grow flex-col justify-between rounded-xl bg-gray-50 p-4">
1717
{/* NOTE: Uncomment this code in Chapter 7 */}
1818

19-
{/* <div className="bg-white px-6">
19+
<div className="bg-white px-6">
2020
{latestInvoices.map((invoice, i) => {
2121
return (
2222
<div
@@ -53,7 +53,7 @@ export default async function LatestInvoices({
5353
</div>
5454
);
5555
})}
56-
</div> */}
56+
</div>
5757
<div className="flex items-center pb-2 pt-6">
5858
<ArrowPathIcon className="h-5 w-5 text-gray-500" />
5959
<h3 className="ml-2 text-sm text-gray-500 ">Updated just now</h3>

0 commit comments

Comments
 (0)