in src/components/graphs/table.tsx [142:458]
export function BlockchainTable({
total,
cb,
}: {
total: number;
cb: (state: unknown) => void;
}) {
const [loading, setLoading] = React.useState(false);
const [data, setData] = React.useState<Block[]>([]);
const [pageIndex, setPageIndex] = React.useState(0);
const [pageSize, setPageSize] = React.useState(10);
// Fetch blocks data
const fetchBlocksData = React.useCallback(async () => {
console.log("Page Idx", pageIndex);
try {
setLoading(true);
const start = pageIndex * pageSize + 1;
const end = Math.min(total, start + pageSize - 1);
cb((prev: { start: number; end: number }) => ({
...prev,
start,
end,
}));
const response = await middlewareApi.get(`/explorer/getBlocks`, {
params: { start, end },
});
console.log("Response is: ", response?.data);
setData(response?.data as Block[]);
setLoading(false);
} catch (error) {
console.error(error);
setLoading(false);
}
}, [pageIndex, pageSize, total]);
// Run fetchBlocksData when pageIndex or pageSize changes
React.useEffect(() => {
fetchBlocksData();
}, [fetchBlocksData]); // Direct dependencies
const totalPages = Math.ceil(total / pageSize);
const handlePageChange = (newPageIndex: number) => {
if (newPageIndex >= 0 && newPageIndex < totalPages) {
console.log("Changing page from", pageIndex, "to", newPageIndex);
setPageIndex(newPageIndex);
}
};
const visiblePages = 5;
const startPage = Math.max(
0,
Math.min(
pageIndex - Math.floor(visiblePages / 2),
totalPages - visiblePages
)
);
const endPage = Math.min(startPage + visiblePages, totalPages);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({});
const table = useReactTable({
data,
columns,
manualPagination: true,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnFilters,
columnVisibility,
pagination: { pageIndex, pageSize },
},
pageCount: totalPages,
});
if (loading) {
return (
<div className="w-full">
<div className="flex items-center py-4">
<Skeleton className="h-8 w-[250px]" />
<Skeleton className="ml-auto h-8 w-[100px]" />
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>
<Skeleton className="h-4 w-[100px]" />
</TableHead>
<TableHead>
<Skeleton className="h-4 w-[100px]" />
</TableHead>
<TableHead>
<Skeleton className="h-4 w-[100px]" />
</TableHead>
<TableHead>
<Skeleton className="h-4 w-[100px]" />
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{[...Array(10)].map((_, index) => (
<TableRow key={index}>
<TableCell>
<Skeleton className="h-4 w-[50px]" />
</TableCell>
<TableCell>
<Skeleton className="h-4 w-[100px]" />
</TableCell>
<TableCell>
<Skeleton className="h-4 w-[50px]" />
</TableCell>
<TableCell>
<Skeleton className="h-4 w-[150px]" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Skeleton className="h-8 w-[80px]" />
<Skeleton className="h-8 w-[80px]" />
</div>
</div>
);
} else {
return (
<div className="w-full">
<div className="flex items-center py-4">
<Input
placeholder="Filter blocks..."
value={
(table.getColumn("number")?.getFilterValue() as string) ?? ""
}
onChange={(event) =>
table.getColumn("number")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto">
Columns <ChevronDown className="ml-2 h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<Select
value={String(pageSize)}
onValueChange={(value) => {
setPageSize(Number(value));
setPageIndex(0);
}}
>
<SelectTrigger className="w-[150px]">
<span>Page Size {pageSize}</span>
</SelectTrigger>
<SelectContent>
{[5, 10, 20, 50, 100, 200].map((size) => (
<SelectItem key={size} value={String(size)}>
Page Size {size}
</SelectItem>
))}
</SelectContent>
</Select>
<Button
variant="outline"
className="ml-4"
onClick={fetchBlocksData}
>
Refresh
</Button>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell
colSpan={columns.length}
className="h-24 text-center"
>
No results...
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
{/* Go to Start Button */}
<Button
variant="outline"
size="sm"
onClick={() => handlePageChange(0)}
disabled={pageIndex === 0}
>
Go to Start
</Button>
{/* Previous Button */}
<Button
variant="outline"
size="sm"
onClick={() => handlePageChange(pageIndex - 1)}
disabled={pageIndex === 0}
>
Previous
</Button>
{/* Page Numbers */}
{Array.from(
{ length: endPage - startPage },
(_, i) => startPage + i
).map((page) => (
<Button
key={page}
variant={page === pageIndex ? "default" : "outline"}
size="sm"
onClick={() => handlePageChange(page)}
>
{page + 1}
</Button>
))}
{/* Next Button */}
<Button
variant="outline"
size="sm"
onClick={() => handlePageChange(pageIndex + 1)}
disabled={pageIndex === totalPages - 1}
>
Next
</Button>
{/* Go to End Button */}
<Button
variant="outline"
size="sm"
onClick={() => handlePageChange(totalPages - 1)}
disabled={pageIndex === totalPages - 1}
>
Go to End
</Button>
</div>
</div>
);
}
}