Skip to content

Commit

Permalink
feat: landing page (#96)
Browse files Browse the repository at this point in the history
Co-authored-by: filip <[email protected]>
  • Loading branch information
Mautjee and FilipHarald authored Oct 7, 2024
1 parent 9cee86a commit e044643
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ export const GET_STATS_TOTAL_TX_EFFECTS = asyncHandler(async (_req, res) => {
res.status(200).send(JSON.stringify(total));
});

export const GET_STATS_TOTAL_TX_EFFECTS_LAST_24H = asyncHandler((_req, res) => {
const txEffects = dbWrapper.get(
export const GET_STATS_TOTAL_TX_EFFECTS_LAST_24H = asyncHandler(async (_req, res) => {
const nbrOfTxEffects = await dbWrapper.get(
["stats", "totalTxEffectsLast24h"],
() => db.l2TxEffect.getTotalTxEffectsLast24h(),
CACHE_LATEST_TTL_SECONDS
);
res.status(200).send(JSON.stringify(txEffects));
res.status(200).send(JSON.stringify(nbrOfTxEffects));
});

export const GET_STATS_TOTAL_CONTRACTS = asyncHandler(async (_req, res) => {
Expand Down
26 changes: 26 additions & 0 deletions services/explorer-ui/src/api/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { aztecExplorer } from "~/service/constants";
import client, { validateResponse } from "./client";
import { z } from "zod";

export const statsL2Api = {
getL2TotalTxEffects: async (): Promise<string> => {
const response = await client.get(aztecExplorer.getL2TotalTxEffects);
return validateResponse(z.string(), response.data);
},
getL2TotalTxEffectsLast24h: async (): Promise<string> => {
const response = await client.get(aztecExplorer.getL2TotalTxEffectsLast24h);
return validateResponse(z.string(), response.data);
},
getL2TotalContracts: async (): Promise<string> => {
const response = await client.get(aztecExplorer.getL2TotalContracts);
return validateResponse(z.string(), response.data);
},
getL2AverageFees: async (): Promise<string> => {
const response = await client.get(aztecExplorer.getL2AverageFees);
return validateResponse(z.string(), response.data);
},
getL2AverageBlockTime: async (): Promise<string> => {
const response = await client.get(aztecExplorer.getL2AverageBlockTime);
return validateResponse(z.string(), response.data);
},
};
97 changes: 75 additions & 22 deletions services/explorer-ui/src/components/blocks/block-table-columns.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { type ColumnDef } from "@tanstack/react-table";
import { Link } from "@tanstack/react-router";
import {routes} from "~/routes/__root";
import { type ColumnDef } from "@tanstack/react-table";
import { DataTableColumnHeader } from "~/components/data-table";
import { formatTimeSince } from "~/lib/utils";
import { routes } from "~/routes/__root";
import type { BlockTableSchema } from "./blocks-schema";
import {formatTimeSince} from "~/lib/utils";

const text = {
height: "BLOCK HEIGHT",
Expand All @@ -17,60 +17,113 @@ const text = {
export const BlockTableColumns: ColumnDef<BlockTableSchema>[] = [
{
accessorKey: "height",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm" column={column} title={text.height} />,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm"
column={column}
title={text.height}
/>
),
cell: ({ row }) => {
const height = row.getValue("height");
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const r = routes.blocks.route + "/" + height;
return (<div className="text-purple-light">
<Link to={r}>{row.getValue("height")}</Link>
</div>);
return (
<div className="text-purple-light">
<Link to={r}>{row.getValue("height")}</Link>
</div>
);
},
enableSorting: true,
enableHiding: false,
},
{
accessorKey: "blockHash",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm text-wrap" column={column} title={text.blockHash} />,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm text-wrap"
column={column}
title={text.blockHash}
/>
),
cell: ({ row }) => {
const blockHash = row.getValue("blockHash");
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const r = routes.blocks.route + "/" + blockHash;
return (<div className="text-purple-light font-mono">
<Link to={r}>{row.getValue("blockHash")}</Link>
</div>);
if (typeof blockHash !== "string") return null;
const r = `${routes.blocks.route}/${blockHash}`;
const truncatedBlockHash = `${blockHash.slice(0, 6)}...${blockHash.slice(
-4
)}`;
return (
<div className="text-purple-light font-mono font-bold">
<Link to={r}>{truncatedBlockHash}</Link>
</div>
);
},
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "numberOfTransactions",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm" column={column} title={text.numberOfTransactions} />,
cell: ({ row }) => <div className="text-purple-dark">{row.getValue("numberOfTransactions")}</div>,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm"
column={column}
title={text.numberOfTransactions}
/>
),
cell: ({ row }) => (
<div className="text-purple-dark">
{row.getValue("numberOfTransactions")}
</div>
),
enableSorting: true,
enableHiding: false,
},
{
accessorKey: "txEffectsLength",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm" column={column} title={text.txEffectsLength} />,
cell: ({ row }) => <div className="text-purple-dark">{row.getValue("txEffectsLength")}</div>,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm"
column={column}
title={text.txEffectsLength}
/>
),
cell: ({ row }) => (
<div className="text-purple-dark">{row.getValue("txEffectsLength")}</div>
),
enableSorting: true,
enableHiding: false,
},
{
accessorKey: "totalFees",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm" column={column} title={text.totalFees} />,
cell: ({ row }) => <div className="text-purple-dark">{row.getValue("totalFees")}</div>,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm"
column={column}
title={text.totalFees}
/>
),
cell: ({ row }) => (
<div className="text-purple-dark">{row.getValue("totalFees")}</div>
),
enableSorting: true,
enableHiding: false,
},
{
accessorKey: "timestamp",
header: ({ column }) => <DataTableColumnHeader className="text-purple-dark text-sm" column={column} title={text.timeSince} />,
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm"
column={column}
title={text.timeSince}
/>
),
cell: ({ row }) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const formattedTime = formatTimeSince(row.getValue("timestamp") as unknown as number * 1000);
return (<div className="text-purple-dark">{formattedTime}</div>);
const formattedTime = formatTimeSince(
(row.getValue("timestamp") as unknown as number) * 1000
);
return <div className="text-purple-dark">{formattedTime}</div>;
},
enableSorting: true,
enableHiding: false,
Expand Down
6 changes: 1 addition & 5 deletions services/explorer-ui/src/components/blocks/blocks-schema.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { z } from "zod";
import { frNumberSchema } from "~/lib/utils";

export type BlockTableSchema = z.infer<typeof blockSchema>;

const frNumberSchema = z.preprocess((val) => {
if (typeof val === "string") return parseInt(val, 16);
return val;
}, z.coerce.number());

export const blockSchema = z.object({
height: z.number(),
blockHash: z.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { Link } from "@tanstack/react-router";
import { routes } from "~/routes/__root";
import { DataTableColumnHeader } from "~/components/data-table";
import { type TxEffectTableSchema } from "./tx-effects-schema";
import { formatTimeSince } from "~/lib/utils";

const text = {
txHash: "TX EFFECT HASH",
transactionFee: "TRANSACTION FEE",
logCount: "LOGS COUNT",
blockHeight: "BLOCK HEIGHT",
timestamp: "TIMESTAMP",
timeSince: "TIME SINCE",
};

export const TxEffectsTableColumns: ColumnDef<TxEffectTableSchema>[] = [
Expand All @@ -24,16 +25,15 @@ export const TxEffectsTableColumns: ColumnDef<TxEffectTableSchema>[] = [
),
cell: ({ row }) => {
const txHash = row.getValue("txHash");
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
const r = routes.txEffects.route + "/" + txHash;
if (typeof txHash !== "string") return null;
const r = `${routes.txEffects.route}/${txHash}`;
const truncatedTxHash = `${txHash.slice(0, 6)}...${txHash.slice(-4)}`;
return (
<div className="text-purple-light font-mono">
<Link to={r}>{row.getValue("txHash")}</Link>
<div className="text-purple-light font-mono font-bold">
<Link to={r}>{truncatedTxHash}</Link>
</div>
);
},
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "transactionFee",
Expand Down Expand Up @@ -84,14 +84,18 @@ export const TxEffectsTableColumns: ColumnDef<TxEffectTableSchema>[] = [
accessorKey: "timestamp",
header: ({ column }) => (
<DataTableColumnHeader
className="text-purple-dark text-sm "
className="text-purple-dark text-sm"
column={column}
title={text.timestamp}
title={text.timeSince}
/>
),
cell: ({ row }) => (
<div className="text-purple-dark">{new Date(row.getValue("timestamp")).toLocaleString()}</div>
),
cell: ({ row }) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const formattedTime = formatTimeSince(
(row.getValue("timestamp") as unknown as number) * 1000
);
return <div className="text-purple-dark">{formattedTime}</div>;
},
enableSorting: true,
enableHiding: false,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from "zod";
import {frNumberSchema} from "~/lib/utils";

export type TxEffectTableSchema = z.infer<typeof txEffectSchema>;

Expand All @@ -7,5 +8,5 @@ export const txEffectSchema = z.object({
transactionFee: z.number(),
logCount: z.number(),
blockNumber: z.number(),
timestamp: z.number(),
timestamp: frNumberSchema,
});
37 changes: 37 additions & 0 deletions services/explorer-ui/src/hooks/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { type UseQueryResult, useQuery } from "@tanstack/react-query";
import { statsL2Api } from "~/api/stats";

export const useTotalTxEffects = (): UseQueryResult<string, Error> => {
return useQuery<string, Error>({
queryKey: ["useTotalTxEffects"],
queryFn: statsL2Api.getL2TotalTxEffects,
});
};

export const useTotalTxEffectsLast24h = (): UseQueryResult<string, Error> => {
return useQuery<string, Error>({
queryKey: ["useTotalTxEffectsLast24h"],
queryFn: statsL2Api.getL2TotalTxEffectsLast24h,
});
};

export const useTotalContracts = (): UseQueryResult<string, Error> => {
return useQuery<string, Error>({
queryKey: ["useTotalContracts"],
queryFn: statsL2Api.getL2TotalContracts,
});
};

export const useAvarageFees = (): UseQueryResult<string, Error> => {
return useQuery<string, Error>({
queryKey: ["useAvarageFees"],
queryFn: statsL2Api.getL2AverageFees,
});
};

export const useAvarageBlockTime = (): UseQueryResult<string, Error> => {
return useQuery<string, Error>({
queryKey: ["useAvarageBlockTime"],
queryFn: statsL2Api.getL2AverageBlockTime,
});
};
18 changes: 12 additions & 6 deletions services/explorer-ui/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { z } from "zod";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
Expand Down Expand Up @@ -62,12 +63,12 @@ export const hexToHSL = (hex: string): string => {
return `hsl(${h}, ${s}%, ${l}%)`;
};

const intervals = [
{ label: "day", seconds: 86400 },
{ label: "hour", seconds: 3600 },
{ label: "minute", seconds: 60 },
{ label: "second", seconds: 1 },
];
const intervals = [
{ label: "day", seconds: 86400 },
{ label: "hour", seconds: 3600 },
{ label: "minute", seconds: 60 },
{ label: "second", seconds: 1 },
];

export const formatTimeSince = (unixTimestamp: number | null) => {
if (unixTimestamp === null) return "no timestamp";
Expand All @@ -82,3 +83,8 @@ export const formatTimeSince = (unixTimestamp: number | null) => {
}
return "just now";
};

export const frNumberSchema = z.preprocess((val) => {
if (typeof val === "string") return parseInt(val, 16);
return val;
}, z.coerce.number());
Loading

0 comments on commit e044643

Please sign in to comment.