mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
Added tanstack react table with dynamic pagination
This commit is contained in:
parent
6b9b7fb7f8
commit
52ff79b02d
4 changed files with 179 additions and 40 deletions
|
|
@ -5,6 +5,7 @@ import {
|
|||
SortingState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
|
|
@ -18,10 +19,32 @@ import {
|
|||
TableRow,
|
||||
} from "@/app/shadcn_components/ui/table";
|
||||
import { useState } from "react";
|
||||
import { DataTablePagination } from "./propertyTablePagination";
|
||||
import { Property } from "./propertyTableColumns";
|
||||
import React from "react";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
columns: ColumnDef<Property>[];
|
||||
data: Property[];
|
||||
}
|
||||
|
||||
function fetchData(offset: number) {
|
||||
// Because this is a client component, this will be handled with react query
|
||||
let properties: Property[] = [];
|
||||
for (let i = offset; i <= offset + 20; i++) {
|
||||
properties.push({
|
||||
id: i,
|
||||
portfolioId: 1,
|
||||
address: `${i}23 Fake Street`,
|
||||
postcode: `AB${i} 2CD`,
|
||||
loadingStatus: Math.random() < 0.5 ? "complete" : "loading",
|
||||
status: "assessment",
|
||||
targetEpc: "C",
|
||||
cost: 1000,
|
||||
});
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
export default function DataTable<TData, TValue>({
|
||||
|
|
@ -29,15 +52,34 @@ export default function DataTable<TData, TValue>({
|
|||
columns,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [tableData, setTableData] = useState<Property[]>(data);
|
||||
const [offset, setOffset] = useState(0);
|
||||
const [currentPageIndex, setCurrentPageIndex] = useState(0);
|
||||
|
||||
// add page change handlers for DataTablePagination
|
||||
const loadPaginatedData = () => {
|
||||
const newData = fetchData(offset);
|
||||
if (newData) {
|
||||
console.log("loadPaginatedData");
|
||||
setTableData([...tableData, ...newData]);
|
||||
setOffset(offset + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const table = useReactTable({
|
||||
data,
|
||||
data: tableData,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
onSortingChange: setSorting,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
|
||||
state: {
|
||||
sorting,
|
||||
pagination: { pageIndex: currentPageIndex, pageSize: 7 },
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -49,7 +91,7 @@ export default function DataTable<TData, TValue>({
|
|||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
<TableHead key={header.id} className="h-14 py-4">
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
|
|
@ -85,6 +127,12 @@ export default function DataTable<TData, TValue>({
|
|||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<DataTablePagination
|
||||
table={table}
|
||||
loadPaginatedData={loadPaginatedData}
|
||||
currentPageIndex={currentPageIndex}
|
||||
setCurrentPageIndex={setCurrentPageIndex}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { Button } from "@/app/shadcn_components/ui/button";
|
|||
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
|
||||
import StatusBadge from "@/app/components/StatusBadge";
|
||||
import { HomeIcon } from "@heroicons/react/20/solid";
|
||||
import { formatNumber } from "@/app/utils";
|
||||
|
||||
export type Property = {
|
||||
id: number;
|
||||
|
|
@ -22,6 +23,7 @@ export type Property = {
|
|||
loadingStatus: string;
|
||||
status: string;
|
||||
targetEpc: string;
|
||||
cost: number;
|
||||
};
|
||||
|
||||
export const columns: ColumnDef<Property>[] = [
|
||||
|
|
@ -80,15 +82,11 @@ export const columns: ColumnDef<Property>[] = [
|
|||
const cost = parseFloat(row.getValue("cost"));
|
||||
|
||||
const loadingStatus = row.original.loadingStatus;
|
||||
console.log("loadingStatus", loadingStatus);
|
||||
if (loadingStatus === "loading") {
|
||||
return <div className="font-medium flex justify-center"></div>;
|
||||
}
|
||||
|
||||
const formatted = new Intl.NumberFormat("en-UK", {
|
||||
style: "currency",
|
||||
currency: "GBP",
|
||||
}).format(cost);
|
||||
const formatted = "£" + formatNumber(cost);
|
||||
|
||||
return (
|
||||
<div className="text-gray-700 font-medium flex justify-center">
|
||||
|
|
@ -137,7 +135,7 @@ export const columns: ColumnDef<Property>[] = [
|
|||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
// onClick={() => navigator.clipboard.writeText(payment.id)}
|
||||
className="cursor-pointer"
|
||||
className="text-gray-700 cursor-pointer"
|
||||
>
|
||||
<a
|
||||
href={`porfolio/${porfolioId}/building-passport/${propertyId}`}
|
||||
|
|
@ -145,6 +143,13 @@ export const columns: ColumnDef<Property>[] = [
|
|||
Building Passport
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
className="text-gray-700 cursor-pointer"
|
||||
// disabled={true}
|
||||
>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
className="text-red-500 focus:text-red-700 cursor-pointer"
|
||||
|
|
|
|||
105
src/app/portfolio/[slug]/components/propertyTablePagination.tsx
Normal file
105
src/app/portfolio/[slug]/components/propertyTablePagination.tsx
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import {
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
ChevronDoubleRightIcon,
|
||||
ChevronDoubleLeftIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Table } from "@tanstack/react-table";
|
||||
|
||||
import { Button } from "@/app/shadcn_components/ui/button";
|
||||
import { useEffect } from "react";
|
||||
|
||||
interface DataTablePaginationProps<TData> {
|
||||
table: Table<TData>;
|
||||
loadPaginatedData: () => void;
|
||||
currentPageIndex: number;
|
||||
setCurrentPageIndex: (index: number) => void;
|
||||
}
|
||||
|
||||
export function DataTablePagination<TData>({
|
||||
table,
|
||||
loadPaginatedData,
|
||||
currentPageIndex,
|
||||
setCurrentPageIndex,
|
||||
}: DataTablePaginationProps<TData>) {
|
||||
// Check if the user has reached the last page
|
||||
|
||||
const requestMoreData = () => {
|
||||
// Check if the next page is the last one
|
||||
if (
|
||||
table.getState().pagination.pageIndex + 1 ===
|
||||
table.getPageCount() - 1
|
||||
) {
|
||||
console.log("requesting more data");
|
||||
loadPaginatedData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToFinalPage = () => {
|
||||
console.log("Go to final page");
|
||||
// Check if the next page is the last one
|
||||
loadPaginatedData();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-end px-2">
|
||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
||||
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
||||
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||
{table.getPageCount()}
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden h-8 w-8 p-0 lg:flex"
|
||||
onClick={() => {
|
||||
setCurrentPageIndex(0);
|
||||
// table.setPageIndex(0);
|
||||
}}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
<span className="sr-only">Go to first page</span>
|
||||
<ChevronDoubleLeftIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-8 w-8 p-0"
|
||||
onClick={() => {
|
||||
setCurrentPageIndex(currentPageIndex - 1);
|
||||
// table.previousPage();
|
||||
}}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
<span className="sr-only">Go to previous page</span>
|
||||
<ChevronLeftIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-8 w-8 p-0"
|
||||
onClick={() => {
|
||||
requestMoreData();
|
||||
setCurrentPageIndex(currentPageIndex + 1);
|
||||
// table.nextPage();
|
||||
}}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
<span className="sr-only">Go to next page</span>
|
||||
<ChevronRightIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="hidden h-8 w-8 p-0 lg:flex"
|
||||
onClick={() => {
|
||||
goToFinalPage();
|
||||
setCurrentPageIndex(table.getPageCount() - 1);
|
||||
}}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
<span className="sr-only">Go to last page</span>
|
||||
<ChevronDoubleRightIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -10,20 +10,12 @@ import { Toolbar } from "@/app/components/portfolio/Toolbar";
|
|||
import DataTable from "@/app/portfolio/[slug]/components/propertyTable";
|
||||
import {
|
||||
columns,
|
||||
Payment,
|
||||
Property,
|
||||
} from "@/app/portfolio/[slug]/components/propertyTableColumns";
|
||||
|
||||
// We enfore caching of data for 60 seconds
|
||||
export const revalidate = 60;
|
||||
|
||||
type Property = {
|
||||
id: string;
|
||||
address: string;
|
||||
postcode: string;
|
||||
loadingStatus: string;
|
||||
status: (typeof PortfolioStatus)[number];
|
||||
};
|
||||
|
||||
function EmptyPropertyState() {
|
||||
return (
|
||||
<div className="flex justify-center h-1/2">
|
||||
|
|
@ -223,31 +215,20 @@ export default async function Page({
|
|||
|
||||
// TODO: TEMP
|
||||
// let properties: Property[];
|
||||
let properties: {}[];
|
||||
let properties: Property[] = [];
|
||||
if (pageStatus === "loading") {
|
||||
properties = [
|
||||
{
|
||||
id: 1,
|
||||
portfolioId: portfolioId,
|
||||
address: "123 Fake Street",
|
||||
postcode: "AB1 2CD",
|
||||
loadingStatus: "loading",
|
||||
for (let i = 1; i <= 20; i++) {
|
||||
properties.push({
|
||||
id: i,
|
||||
portfolioId: 1,
|
||||
address: `${i}23 Fake Street`,
|
||||
postcode: `AB${i} 2CD`,
|
||||
loadingStatus: Math.random() < 0.5 ? "complete" : "loading",
|
||||
status: "assessment",
|
||||
targetEpc: "C",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
portfolioId: portfolioId,
|
||||
address: "223 Fake Street",
|
||||
postcode: "AB1 2CD",
|
||||
loadingStatus: "complete",
|
||||
cost: 1000,
|
||||
status: "assessment",
|
||||
targetEpc: "C",
|
||||
},
|
||||
];
|
||||
} else {
|
||||
properties = [];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue