Skip to content

Commit

Permalink
extra menu
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtemkaDev committed Nov 24, 2024
1 parent dddf04f commit 9b2c25c
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 62 deletions.
17 changes: 3 additions & 14 deletions src/components/crypto/charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,8 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { formatHashrate } from "./utils";

function formatHashrate(difficulty: any): string {
const units = ["H/s", "KH/s", "MH/s", "GH/s", "TH/s", "PH/s"];
let value = Number(difficulty);
let unitIndex = 0;

while (value >= 1000 && unitIndex < units.length - 1) {
value /= 1000;
unitIndex++;
}

return `${value.toFixed(2)} ${units[unitIndex]}`;
}
const chartConfig = {
difficulty: {
label: "Difficulty",
Expand Down Expand Up @@ -89,7 +78,7 @@ export const Charts = () => {
gasUsed: (
(Number(block.gasUsed) / Number(block.gasLimit)) *
100
).toString(),
).toFixed(2),
transactions: block.transactions.length,
};
}
Expand All @@ -111,7 +100,7 @@ export const Charts = () => {

const gasData = blocks.map((block) => ({
name: `${block.number}`,
gasused: Math.min(100, parseFloat(Number(block.gasUsed).toFixed(2))),
gasused: block.gasUsed ,
transactions: block.transactions,
}));
return (
Expand Down
195 changes: 147 additions & 48 deletions src/components/crypto/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@ import { useEffect, useState, useCallback } from "react";
import { ethers } from "ethers";
import {
ColumnDef,
ColumnFiltersState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { ChevronDown, MoreHorizontal } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
DropdownMenuCheckboxItem,
} from "@/components/ui/dropdown-menu";
import {
Table,
Expand All @@ -38,10 +48,14 @@ import {
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import {formatHashrate} from "./utils";

type Block = {
number: number;
number: string;
difficulty: string;
gasused: string;
miner: string;
timestamp: string;
};
Expand All @@ -54,6 +68,20 @@ export const columns: ColumnDef<Block>[] = [
<div className="capitalize">{row.getValue("number")}</div>
),
},
{
accessorKey: "difficulty",
header: "Difficulty",
cell: ({ row }) => (
<div className="capitalize">{row.getValue("difficulty")}</div>
),
},
{
accessorKey: "gasused",
header: "Gas used",
cell: ({ row }) => (
<div className="capitalize">{row.getValue("gasused")}%</div>
),
},
{
accessorKey: "timestamp",
header: "Timestamp",
Expand Down Expand Up @@ -128,17 +156,31 @@ export default function Info() {
const [sorting, setSorting] = useState<SortingState>([]);
const [maxBlocks, setMaxBlocks] = useState(20);
const [customBlockLimit, setCustomBlockLimit] = useState("");
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({
difficulty: false,
gasused: false
});
const [rowSelection, setRowSelection] = React.useState({});

const fetchLatestBlock = useCallback(async () => {
const latestBlockNumber = await provider.getBlockNumber();
const block = await provider.getBlock(latestBlockNumber);
if (block) {
setBlocks((prevBlocks) => {
if (prevBlocks.length && prevBlocks[0].number === block.number) {
if (
prevBlocks.length &&
Number(prevBlocks[0].number) === block.number
) {
return prevBlocks;
}
const newBlock = {
number: block.number,
number: block.number.toString(),
difficulty: formatHashrate(block.difficulty),
gasused: (Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2),
miner: block.miner,
timestamp: block.timestamp.toString(),
};
Expand All @@ -161,7 +203,9 @@ export default function Info() {
const formattedBlocks = blocks
.filter((block): block is ethers.Block => block !== null)
.map((block) => ({
number: block.number,
number: block.number.toString(),
difficulty: formatHashrate(block.difficulty),
gasused: (Number(block.gasUsed) / Number(block.gasLimit) * 100).toFixed(2),
miner: block.miner,
timestamp: block.timestamp.toString(),
}));
Expand All @@ -177,64 +221,119 @@ export default function Info() {
const table = useReactTable({
data: blocks,
columns,
state: { sorting },
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onColumnFiltersChange: setColumnFilters,
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
});

return (
<div className="w-full pl-4">
<div className="flex items-center justify-end py-4">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">
Block Limit: {maxBlocks} <ChevronDown className="ml-2 h-4 w-4" />
</Button>
<Button variant="outline">Settings</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>Choose Block Limit</DropdownMenuLabel>
<DropdownMenuLabel>Settings</DropdownMenuLabel>
<DropdownMenuSeparator />
{[100, 500, 1000, 2000].map((limit) => (
<>
<DropdownMenuItem
key={limit}
onClick={async () => {
setMaxBlocks(limit);
fetchInitialBlocks();
}}
>
{limit} blocks
</DropdownMenuItem>
<DropdownMenuSeparator className="bg-border" />
</>
))}
<DropdownMenuGroup>
{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>
);
})}
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
Block Limit: {maxBlocks}
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuLabel>Choose Block Limit</DropdownMenuLabel>
<DropdownMenuSeparator />
{[100, 500, 1000, 2000].map((limit) => (
<>
<DropdownMenuItem
key={limit}
onClick={async () => {
setMaxBlocks(limit);
fetchInitialBlocks();
}}
>
{limit} blocks
</DropdownMenuItem>
<DropdownMenuSeparator className="bg-border" />
</>
))}

<div className="p-2">
<div className="flex items-center space-x-2">
<input
type="number"
value={customBlockLimit}
onChange={(e) => setCustomBlockLimit(e.target.value)}
placeholder="Custom limit"
className="flex h-8 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
/>
<Button
className="rounded-md border"
variant="secondary"
size="sm"
onClick={() => {
const limit = parseInt(customBlockLimit);
if (limit > 0) {
setMaxBlocks(limit);
fetchInitialBlocks();
}
}}
>
Set
</Button>
</div>
</div>
<div className="p-2">
<div className="flex items-center space-x-2">
<input
type="number"
value={customBlockLimit}
onChange={(e) => setCustomBlockLimit(e.target.value)}
placeholder="Custom limit"
className="flex h-8 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
/>
<Button
className="rounded-md border"
variant="secondary"
size="sm"
onClick={() => {
const limit = parseInt(customBlockLimit);
if (limit > 0) {
setMaxBlocks(limit);
fetchInitialBlocks();
}
}}
>
Set
</Button>
</div>
</div>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<Input
placeholder="Filter blocks..."
value={
(table.getColumn("number")?.getFilterValue() as string) ?? ""
}
onChange={(event) => {
console.log(event.target.value);
table
.getColumn("number")
?.setFilterValue(event.target.value.toString());
}}
className="max-w-sm"
/>
</DropdownMenuContent>
</DropdownMenu>
</div>
Expand Down
12 changes: 12 additions & 0 deletions src/components/crypto/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function formatHashrate(difficulty: any): string {
const units = ["H/s", "KH/s", "MH/s", "GH/s", "TH/s", "PH/s"];
let value = Number(difficulty);
let unitIndex = 0;

while (value >= 1000 && unitIndex < units.length - 1) {
value /= 1000;
unitIndex++;
}

return `${value.toFixed(2)} ${units[unitIndex]}`;
}

0 comments on commit 9b2c25c

Please sign in to comment.