diff --git a/dashboard/15-final/app/dashboard/invoices/page.tsx b/dashboard/15-final/app/dashboard/invoices/page.tsx index fcf178aa..fd35c3f9 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 61b94a08..b5e75d5f 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` + const invoices = await sql` SELECT invoices.id, invoices.amount, @@ -105,34 +105,37 @@ export async function fetchFilteredInvoices( invoices.date::text ILIKE ${`%${query}%`} OR invoices.status ILIKE ${`%${query}%`} ORDER BY invoices.date DESC - LIMIT ${itemsPerPage} OFFSET ${offset} + LIMIT ${ITEMS_PER_PAGE} OFFSET ${offset} `; - const count = await sql` - SELECT COUNT(*) - FROM invoices - JOIN customers ON invoices.customer_id = customers.id - WHERE - customers.name ILIKE ${`%${query}%`} OR - customers.email ILIKE ${`%${query}%`} OR - invoices.amount::text ILIKE ${`%${query}%`} OR - invoices.date::text ILIKE ${`%${query}%`} OR - invoices.status ILIKE ${`%${query}%`} - `; - - const totalRecords = Number(count.rows[0].count); - const totalPages = Math.ceil(totalRecords / itemsPerPage); - - return { - invoices: data.rows, - totalPages, - }; + return invoices.rows; } catch (error) { console.error('Database Error:', error); throw new Error('Failed to fetch invoices.'); } } +export async function fetchInvoicesPages(query: string) { + try { + const count = await sql`SELECT COUNT(*) + FROM invoices + JOIN customers ON invoices.customer_id = customers.id + WHERE + customers.name ILIKE ${`%${query}%`} OR + customers.email ILIKE ${`%${query}%`} OR + invoices.amount::text ILIKE ${`%${query}%`} OR + invoices.date::text ILIKE ${`%${query}%`} OR + invoices.status ILIKE ${`%${query}%`} + `; + + const totalPages = Math.ceil(Number(count.rows[0].count) / ITEMS_PER_PAGE); + return totalPages; + } catch (error) { + console.error('Database Error:', error); + throw new Error('Failed to fetch total number of invoices.'); + } +} + export async function fetchInvoiceById(id: string) { try { const data = await sql` diff --git a/dashboard/15-final/app/ui/dashboard/skeletons.tsx b/dashboard/15-final/app/ui/dashboard/skeletons.tsx index cdab3bad..c57322d1 100644 --- a/dashboard/15-final/app/ui/dashboard/skeletons.tsx +++ b/dashboard/15-final/app/ui/dashboard/skeletons.tsx @@ -90,3 +90,118 @@ export default function DashboardSkeleton() { ); } + +export function TableRowSkeleton() { + return ( + + {/* Customer Name and Image */} + + {/* Email */} + + {/* Amount */} + + {/* Date */} + + {/* Status */} + + {/* Actions */} + + + ); +} + +export function InvoicesMobileSkeleton() { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); +} + +export function InvoicesTableSkeleton() { + return ( +
+
+
+
+ + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ Customer + + Email + + Amount + + Date + + Status + + Edit +
+ + + + ); +} diff --git a/dashboard/15-final/app/ui/invoices/pagination.tsx b/dashboard/15-final/app/ui/invoices/pagination.tsx index a9c6dbaa..e9d0293a 100644 --- a/dashboard/15-final/app/ui/invoices/pagination.tsx +++ b/dashboard/15-final/app/ui/invoices/pagination.tsx @@ -6,15 +6,11 @@ import Link from 'next/link'; import { generatePagination } from '@/app/lib/utils'; import { usePathname, useSearchParams } from 'next/navigation'; -export default function Pagination({ - currentPage, - totalPages, -}: { - currentPage: number; - totalPages: number; -}) { +export default function Pagination({ totalPages }: { totalPages: number }) { const pathname = usePathname(); const searchParams = useSearchParams(); + const currentPage = Number(searchParams.get('page')) || 1; + const allPages = generatePagination(currentPage, totalPages); const createPageURL = (pageNumber: number | string) => { const params = new URLSearchParams(searchParams); @@ -22,8 +18,6 @@ export default function Pagination({ return `${pathname}?${params.toString()}`; }; - const allPages = generatePagination(currentPage, totalPages); - return (
- -
-
-
-
+
+
+
+ {invoices?.map((invoice) => ( +
+
+
+
+ {`${invoice.name}'s +

{invoice.name}

+
+

{invoice.email}

+
+ +
+
+
+

+ {formatCurrency(invoice.amount)} +

+

{formatDateToLocal(invoice.date)}

+
+
+ + +
+
+
+ ))} +
+ + + + + + + + + + + + {invoices?.map((invoice) => ( -
-
-
-
- -

{invoice.name}

-
-

{invoice.email}

+
+ + + + + +
+ Customer + + Email + + Amount + + Date + + Status + + Edit +
+
+ {`${invoice.name}'s +

{invoice.name}

+
+ {invoice.email} + + {formatCurrency(invoice.amount)} + + {formatDateToLocal(invoice.date)} + - -
-
-

- {formatCurrency(invoice.amount)} -

-

{formatDateToLocal(invoice.date)}

-
-
+
+
- - - ))} - - - - - - - - - - + - - - {invoices?.map((invoice) => ( - - - - - - - - - ))} - -
- Customer - - Email - - Amount - - Date - - Status - - Edit -
-
- {`${invoice.name}'s -

{invoice.name}

-
-
- {invoice.email} - - {formatCurrency(invoice.amount)} - - {formatDateToLocal(invoice.date)} - - - - - -
- + ))} +