Skip to content

Commit 02151f6

Browse files
Add loading component and update dashboard page
1 parent 9c50e57 commit 02151f6

File tree

7 files changed

+83
-53
lines changed

7 files changed

+83
-53
lines changed

app/dashboard/(overview)/loading.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import DashboardSkeleton from "../../ui/skeletons"
2+
3+
export default function Loading() {
4+
return <DashboardSkeleton />
5+
}

app/dashboard/(overview)/page.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Card } from '../../ui/dashboard/cards';
2+
import RevenueChart from '../../ui/dashboard/revenue-chart';
3+
import LatestInvoices from '../../ui/dashboard/latest-invoices';
4+
import { lusitana } from '../../ui/fonts';
5+
import { Suspense } from 'react';
6+
import CardWrapper from '../../ui/dashboard/cards';
7+
import {
8+
InvoiceSkeleton,
9+
RevenueChartSkeleton,
10+
CardSkeleton,
11+
} from '@/app/ui/skeletons';
12+
13+
export default async function Page() {
14+
return (
15+
<main>
16+
<h1 className={`${lusitana.className} md:text-2x1 mb-4 text-xl`}>
17+
Dashboard
18+
</h1>
19+
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
20+
<Suspense fallback={<CardSkeleton />}>
21+
<CardWrapper />
22+
</Suspense>
23+
</div>
24+
<div className="mt-6 grid grid-cols-1 gap-6 md:grid-cols-4 lg:grid-cols-8">
25+
<Suspense fallback={<RevenueChartSkeleton />}>
26+
<RevenueChart />
27+
</Suspense>
28+
<Suspense fallback={<InvoiceSkeleton />}>
29+
<LatestInvoices />
30+
</Suspense>
31+
</div>
32+
</main>
33+
);
34+
}

app/dashboard/page.tsx

Lines changed: 0 additions & 33 deletions
This file was deleted.

app/lib/data.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@ import {
99
Revenue,
1010
} from './definitions';
1111
import { formatCurrency } from './utils';
12+
import { unstable_noStore as noStore } from 'next/cache';
1213

1314
export async function fetchRevenue() {
14-
// Add noStore() here prevent the response from being cached.
15-
// This is equivalent to in fetch(..., {cache: 'no-store'}).
15+
noStore();
1616

1717
try {
1818
// Artificially delay a response for demo purposes.
1919
// Don't do this in production :)
2020

21-
// console.log('Fetching revenue data...');
22-
// await new Promise((resolve) => setTimeout(resolve, 3000));
21+
console.log('Fetching revenue data...');
22+
await new Promise((resolve) => setTimeout(resolve, 3000));
2323

2424
const data = await sql<Revenue>`SELECT * FROM revenue`;
2525

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

2828
return data.rows;
2929
} catch (error) {
@@ -33,7 +33,15 @@ export async function fetchRevenue() {
3333
}
3434

3535
export async function fetchLatestInvoices() {
36+
noStore();
37+
3638
try {
39+
// Artificially delay a response for demo purposes.
40+
// Don't do this in production :)
41+
42+
console.log('Fetching latest invoice data...');
43+
await new Promise((resolve) => setTimeout(resolve, 1600));
44+
3745
const data = await sql<LatestInvoiceRaw>`
3846
SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id
3947
FROM invoices
@@ -53,6 +61,13 @@ export async function fetchLatestInvoices() {
5361
}
5462

5563
export async function fetchCardData() {
64+
// Artificially delay a response for demo purposes.
65+
// Don't do this in production :)
66+
67+
console.log('Fetching latest invoice data...');
68+
await new Promise((resolve) => setTimeout(resolve, 800));
69+
noStore();
70+
5671
try {
5772
// You can probably combine these into a single SQL query
5873
// However, we are intentionally splitting them to demonstrate
@@ -93,6 +108,7 @@ export async function fetchFilteredInvoices(
93108
currentPage: number,
94109
) {
95110
const offset = (currentPage - 1) * ITEMS_PER_PAGE;
111+
noStore();
96112

97113
try {
98114
const invoices = await sql<InvoicesTable>`
@@ -124,6 +140,8 @@ export async function fetchFilteredInvoices(
124140
}
125141

126142
export async function fetchInvoicesPages(query: string) {
143+
noStore();
144+
127145
try {
128146
const count = await sql`SELECT COUNT(*)
129147
FROM invoices
@@ -145,6 +163,8 @@ export async function fetchInvoicesPages(query: string) {
145163
}
146164

147165
export async function fetchInvoiceById(id: string) {
166+
noStore();
167+
148168
try {
149169
const data = await sql<InvoiceForm>`
150170
SELECT

app/ui/dashboard/cards.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
InboxIcon,
66
} from '@heroicons/react/24/outline';
77
import { lusitana } from '@/app/ui/fonts';
8+
import { fetchCardData } from '@/app/lib/data';
89

910
const iconMap = {
1011
collected: BanknotesIcon,
@@ -14,18 +15,23 @@ const iconMap = {
1415
};
1516

1617
export default async function CardWrapper() {
18+
const {
19+
numberOfInvoices,
20+
numberOfCustomers,
21+
totalPaidInvoices,
22+
totalPendingInvoices,
23+
} = await fetchCardData();
24+
1725
return (
1826
<>
19-
{/* NOTE: comment in this code when you get to this point in the course */}
20-
21-
{/* <Card title="Collected" value={totalPaidInvoices} type="collected" />
27+
<Card title="Collected" value={totalPaidInvoices} type="collected" />
2228
<Card title="Pending" value={totalPendingInvoices} type="pending" />
2329
<Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
2430
<Card
2531
title="Total Customers"
2632
value={numberOfCustomers}
2733
type="customers"
28-
/> */}
34+
/>
2935
</>
3036
);
3137
}

app/ui/dashboard/latest-invoices.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import { ArrowPathIcon } from '@heroicons/react/24/outline';
22
import clsx from 'clsx';
33
import Image from 'next/image';
44
import { lusitana } from '@/app/ui/fonts';
5-
import { LatestInvoice } from '@/app/lib/definitions';
6-
export default async function LatestInvoices({
7-
latestInvoices,
8-
}: {
9-
latestInvoices: LatestInvoice[];
10-
}) {
5+
import { fetchLatestInvoices } from '@/app/lib/data';
6+
7+
export default async function LatestInvoices() {
8+
const latestInvoices = await fetchLatestInvoices();
9+
1110
return (
1211
<div className="flex w-full flex-col md:col-span-4">
1312
<h2 className={`${lusitana.className} mb-4 text-xl md:text-2xl`}>

app/ui/dashboard/revenue-chart.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@ import { generateYAxis } from '@/app/lib/utils';
22
import { CalendarIcon } from '@heroicons/react/24/outline';
33
import { lusitana } from '@/app/ui/fonts';
44
import { Revenue } from '@/app/lib/definitions';
5+
import { fetchRevenue } from '@/app/lib/data';
56

67
// This component is representational only.
78
// For data visualization UI, check out:
89
// https://www.tremor.so/
910
// https://www.chartjs.org/
1011
// https://airbnb.io/visx/
1112

12-
export default async function RevenueChart({
13-
revenue,
14-
}: {
15-
revenue: Revenue[];
16-
}) {
13+
export default async function RevenueChart() {
14+
const revenue = await fetchRevenue();
15+
1716
const chartHeight = 350;
1817

1918
const { yAxisLabels, topLabel } = generateYAxis(revenue);

0 commit comments

Comments
 (0)