-
-
-
-
- {pagesToShow.map((page, i) => {
- if (page === '...') {
- return (
-
- ...
-
- );
- }
+
+
+
+ {allPages.map((page, index) => {
+ let position: 'first' | 'last' | 'single' | 'middle' | undefined;
+
+ if (index === 0) position = 'first';
+ if (index === allPages.length - 1) position = 'last';
+ if (allPages.length === 1) position = 'single';
+ if (page === '...') position = 'middle';
- const PageTag = page === currentPage || page === '...' ? 'p' : Link;
return (
-
- {page}
-
+ href={createPageURL(page)}
+ page={page}
+ position={position}
+ isActive={currentPage === page}
+ />
);
})}
-
-
-
+
+
= totalPages}
+ />
);
}
+
+function PaginationNumber({
+ page,
+ href,
+ isActive,
+ position,
+}: {
+ page: number | string;
+ href: string;
+ position?: 'first' | 'last' | 'middle' | 'single';
+ isActive: boolean;
+}) {
+ const className = clsx(
+ 'flex h-10 w-10 items-center justify-center text-sm border',
+ {
+ 'rounded-l-md': position === 'first' || position === 'single',
+ 'rounded-r-md': position === 'last' || position === 'single',
+ 'z-10 bg-blue-600 border-blue-600 text-white': isActive,
+ 'hover:bg-gray-100': !isActive && position !== 'middle',
+ 'text-gray-300': position === 'middle',
+ },
+ );
+
+ return isActive || position === 'middle' ? (
+
{page}
+ ) : (
+
+ {page}
+
+ );
+}
+
+function PaginationArrow({
+ href,
+ direction,
+ isDisabled,
+}: {
+ href: string;
+ direction: 'left' | 'right';
+ isDisabled?: boolean;
+}) {
+ const className = clsx(
+ 'flex h-10 w-10 items-center justify-center rounded-md border',
+ {
+ 'pointer-events-none text-gray-300': isDisabled,
+ 'hover:bg-gray-100': !isDisabled,
+ 'mr-2 md:mr-4': direction === 'left',
+ 'ml-2 md:ml-4': direction === 'right',
+ },
+ );
+
+ const icon =
+ direction === 'left' ? (
+
+ ) : (
+
+ );
+
+ return isDisabled ? (
+
{icon}
+ ) : (
+
+ {icon}
+
+ );
+}
diff --git a/dashboard/15-final/app/ui/search.tsx b/dashboard/15-final/app/ui/search.tsx
index bb58994..7c89054 100644
--- a/dashboard/15-final/app/ui/search.tsx
+++ b/dashboard/15-final/app/ui/search.tsx
@@ -13,6 +13,8 @@ export default function Search({ placeholder }: { placeholder: string }) {
console.log(`Searching... ${term}`);
const params = new URLSearchParams(searchParams);
+
+ params.set('page', '1');
if (term) {
params.set('query', term);
} else {
From c6413f9037087e8f9e0b0901c16dcc45d7c940bc Mon Sep 17 00:00:00 2001
From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
Date: Tue, 10 Oct 2023 14:04:46 +0100
Subject: [PATCH 3/6] Add table loading skeletons and move data fetching down
(#207)
* Use tailwind variants
* Move data fetching down
* Add table skeleton
* Update pagination data fetching
* Fix skeleton layout shift
* Add key to suspense to trigger it on subsequent navigation
---
.../15-final/app/dashboard/invoices/page.tsx | 18 +-
dashboard/15-final/app/lib/data.ts | 49 ++--
.../15-final/app/ui/dashboard/skeletons.tsx | 115 +++++++++
.../15-final/app/ui/invoices/pagination.tsx | 12 +-
dashboard/15-final/app/ui/invoices/table.tsx | 221 ++++++++----------
5 files changed, 255 insertions(+), 160 deletions(-)
diff --git a/dashboard/15-final/app/dashboard/invoices/page.tsx b/dashboard/15-final/app/dashboard/invoices/page.tsx
index fcf178a..fd35c3f 100644
--- a/dashboard/15-final/app/dashboard/invoices/page.tsx
+++ b/dashboard/15-final/app/dashboard/invoices/page.tsx
@@ -2,8 +2,10 @@ import Pagination from '@/app/ui/invoices/pagination';
import Search from '@/app/ui/search';
import { CreateInvoice } from '@/app/ui/invoices/buttons';
import Table from '@/app/ui/invoices/table';
-import { fetchFilteredInvoices } from '@/app/lib/data';
import { lusitana } from '@/app/ui/fonts';
+import { InvoicesTableSkeleton } from '@/app/ui/dashboard/skeletons';
+import { Suspense } from 'react';
+import { fetchInvoicesPages } from '@/app/lib/data';
export default async function Page({
searchParams,
@@ -14,12 +16,8 @@ export default async function Page({
};
}) {
const query = searchParams?.query || '';
- const currentPage = Number(searchParams?.page || '1');
-
- const { invoices, totalPages } = await fetchFilteredInvoices(
- query,
- currentPage,
- );
+ const currentPage = Number(searchParams?.page) || 1;
+ const totalPages = await fetchInvoicesPages(query);
return (
@@ -30,9 +28,11 @@ export default async function Page({
-
+
}>
+
+
);
diff --git a/dashboard/15-final/app/lib/data.ts b/dashboard/15-final/app/lib/data.ts
index 61b94a0..b5e75d5 100644
--- a/dashboard/15-final/app/lib/data.ts
+++ b/dashboard/15-final/app/lib/data.ts
@@ -79,15 +79,15 @@ export async function fetchCardData() {
}
}
+const ITEMS_PER_PAGE = 6;
export async function fetchFilteredInvoices(
query: string,
currentPage: number,
) {
- const itemsPerPage = 6;
- const offset = (currentPage - 1) * itemsPerPage;
+ const offset = (currentPage - 1) * ITEMS_PER_PAGE;
try {
- const data = await sql