Skip to content

Commit 28e5d9d

Browse files
authored
ui: contract page mobile friendly (#144)
1 parent a40adf6 commit 28e5d9d

File tree

18 files changed

+302
-306
lines changed

18 files changed

+302
-306
lines changed

services/explorer-ui/src/components/contracts/class-and-instance-tables.tsx

-79
This file was deleted.

services/explorer-ui/src/components/info-badge.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ export const InfoBadge: FC<InfoBadgeProps> = ({
2121

2222
return (
2323
<div className="flex flex-col bg-white w-5/12 justify-between rounded-lg shadow-md p-4 md:w-96">
24-
<p>{title}</p>
25-
<h2 className="text-primary">{text}</h2>
24+
<p className="text-sm">{title}</p>
25+
<h3 className="text-primary">{text}</h3>
2626
</div>
2727
);
2828
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { FC, useMemo } from "react";
2+
3+
interface TableBadgeProps {
4+
title: string;
5+
isLoading: boolean;
6+
error: Error | null;
7+
children: React.ReactNode;
8+
}
9+
10+
export const TableBadge: FC<TableBadgeProps> = ({
11+
title,
12+
isLoading,
13+
error,
14+
children,
15+
}) => {
16+
const text = useMemo(() => {
17+
if (isLoading) return "Loading";
18+
if (error) return error.message;
19+
return undefined;
20+
}, [isLoading, error]);
21+
22+
return (
23+
<div className="bg-white w-full rounded-lg shadow-md p-4 md:w-1/2">
24+
<h3>{title}</h3>
25+
{!text ? children : <p className="text-primary-500">{text}</p>}
26+
</div>
27+
);
28+
};

services/explorer-ui/src/pages/block-details/index.tsx

+5-17
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,18 @@ export const BlockDetails: FC = () => {
3535
<a href={apiEndpointUrl} target="_blank" rel="noreferrer">
3636
(API Endpoint)
3737
</a>
38-
</div>
39-
<div className="flex flex-col gap-4 mt-8">
40-
<div className="bg-white rounded-lg shadow-md p-4">
41-
<KeyValueDisplay data={getBlockDetails(latestBlock)} />
42-
</div>
43-
<div className="flex flex-row gap-4 w-10 mb-4">
44-
<Button
45-
variant={"default"}
46-
className={"shadow-[0px_0px_1px_2px_rgba(0,0,0,1)]"}
47-
>
48-
<p>View TxEffects</p>
49-
</Button>
50-
</div>
51-
<TxEffectsTable txEffects={getTxEffects(latestBlock)} />
52-
</div>
38+
</div>
5339
<div className="flex flex-col gap-4 mt-8">
5440
<div className="bg-white rounded-lg shadow-md p-4">
5541
<KeyValueDisplay data={getBlockDetails(latestBlock)} />
5642
</div>
5743
<div className="flex flex-row gap-4 w-10 mb-4">
58-
<Button variant={"default"}>
44+
<Button
45+
variant={"default"}
46+
className={"shadow-[0px_0px_1px_2px_rgba(0,0,0,1)]"}
47+
>
5948
<p>View TxEffects</p>
6049
</Button>
61-
<Button variant={"default"}>View TxEffects</Button>
6250
</div>
6351
<TxEffectsTable txEffects={getTxEffects(latestBlock)} />
6452
</div>

services/explorer-ui/src/pages/block/index.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@ export const Blocks: FC = () => {
2323
if (error) return <p className="text-red-500">{error.message}</p>;
2424
if (!latestBlocks) return <p>No data</p>;
2525
const averageBlockTimeFormatted = formatDuration(
26-
Number(avarageBlockTime) / 1000
26+
Number(avarageBlockTime) / 1000,
2727
);
2828

2929
return (
30-
<div className="mx-auto px-[70px] max-w-[1440px]">
31-
<h1 className="mt-16">Latest Blocks</h1>
30+
<div className="mx-auto px-5 max-w-[1440px] md:px-[70px]">
31+
<div className="flex flex-wrap justify-center gap-3 m-5 ">
32+
<h2 className="mt-2 text-primary md:hidden">Blocks</h2>
33+
<h1 className="hidden md:block md:mt-16">Blocks</h1>
34+
</div>
3235
<div className="flex flex-row justify-center gap-4 m-8">
3336
<InfoBadge
3437
title="Average fees (FPA)"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { useParams } from "@tanstack/react-router";
2+
import { type FC } from "react";
3+
import { KeyValueDisplay } from "~/components/info-display/key-value-display";
4+
import { useContractClasses, useContractInstance } from "~/hooks";
5+
import { API_URL, aztecExplorer } from "~/service/constants";
6+
import { getContractData } from "./util";
7+
import { ContractInstancesTable } from "~/components/contracts/instances/table";
8+
import { mapContractClasses, mapContractInstances } from "../contract/util";
9+
import { TableBadge } from "~/components/table-badge";
10+
import { ContractClassesTable } from "~/components/contracts/classes/table";
11+
12+
export const ContractClassDetails: FC = () => {
13+
const { id } = useParams({
14+
from: "/contracts/classes/$id",
15+
});
16+
const {
17+
data: classesData,
18+
isLoading: isLoadingClasses,
19+
error: errorClasses,
20+
} = useContractClasses(id);
21+
const {
22+
data: instancesData,
23+
isLoading: isLoadingInstances,
24+
error: errorInstances,
25+
} = useContractInstance(id);
26+
27+
if (!id) return <div>No classId</div>;
28+
29+
const apiEndpointUrl = `${API_URL}/${aztecExplorer.getL2ContractClasses(id)}`;
30+
31+
return (
32+
<div className="mx-auto px-[70px] max-w-[1440px]">
33+
<div className="flex flex-col gap-4 mt-8">
34+
<div>
35+
<div>
36+
<h2>Contract class details</h2>
37+
<a href={apiEndpointUrl} target="_blank" rel="noreferrer">
38+
(API Endpoint)
39+
</a>
40+
</div>
41+
<div className="flex flex-col gap-4 mt-8">
42+
<div className="bg-white rounded-lg shadow-md p-4">
43+
<KeyValueDisplay
44+
data={classesData ? getContractData(classesData[0]) : []}
45+
/>
46+
</div>
47+
</div>
48+
</div>
49+
<div className="flex flex-col gap-4 md:flex-row ">
50+
<TableBadge
51+
title="Total Contract Instances"
52+
isLoading={isLoadingClasses}
53+
error={errorClasses}
54+
>
55+
{classesData && (
56+
<ContractClassesTable
57+
contracts={mapContractClasses(classesData)}
58+
/>
59+
)}
60+
</TableBadge>
61+
62+
<TableBadge
63+
title="Total Contract Instances"
64+
isLoading={isLoadingInstances}
65+
error={errorInstances}
66+
>
67+
{instancesData && (
68+
<ContractInstancesTable
69+
contracts={mapContractInstances([instancesData])}
70+
/>
71+
)}
72+
</TableBadge>
73+
</div>
74+
</div>
75+
</div>
76+
);
77+
};

services/explorer-ui/src/pages/contracts/instance-details/index.tsx services/explorer-ui/src/pages/contract-instance-details/index.tsx

+4-11
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,9 @@ import { API_URL, aztecExplorer } from "~/service/constants";
66
import { getContractData } from "./util";
77

88
export const ContractInstanceDetails: FC = () => {
9-
let address = "";
10-
try {
11-
const params = useParams({
12-
from: "/contracts/instances/$address",
13-
});
14-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
15-
address = params.address;
16-
} catch (e) {
17-
// TODO
18-
}
9+
const { address } = useParams({
10+
from: "/contracts/instances/$address",
11+
});
1912
const {
2013
data: contractInstanceDetails,
2114
isLoading,
@@ -28,7 +21,7 @@ export const ContractInstanceDetails: FC = () => {
2821
if (!contractInstanceDetails) return <div>No data</div>;
2922

3023
const apiEndpointUrl = `${API_URL}/${aztecExplorer.getL2ContractInstance(
31-
address
24+
address,
3225
)}`;
3326

3427
return (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { FC } from "react";
2+
import { InfoBadge } from "~/components/info-badge";
3+
import { useLatestContractClasses, useLatestContractInstances } from "~/hooks";
4+
import { useTotalContracts, useTotalContractsLast24h } from "~/hooks/stats";
5+
import { mapContractClasses, mapContractInstances } from "./util";
6+
import { ContractInstancesTable } from "~/components/contracts/instances/table";
7+
import { ContractClassesTable } from "~/components/contracts/classes/table";
8+
import { TableBadge } from "~/components/table-badge";
9+
10+
export const Contracts: FC = () => {
11+
const {
12+
data: classesData,
13+
isLoading: isLoadingClasses,
14+
error: errorClasses,
15+
} = useLatestContractClasses();
16+
const {
17+
data: instancesData,
18+
isLoading: isLoadingInstances,
19+
error: errorInstances,
20+
} = useLatestContractInstances();
21+
const {
22+
data: totalAmountOfContracts,
23+
isLoading: loadingAmountContracts,
24+
error: errorAmountContracts,
25+
} = useTotalContracts();
26+
const {
27+
data: totalAmountOfContracts24h,
28+
isLoading: loadingAmountContracts24h,
29+
error: errorAmountContracts24h,
30+
} = useTotalContractsLast24h();
31+
32+
return (
33+
<div className="mx-auto px-7 max-w-[1440px] md:px-[70px]">
34+
<div className="flex flex-wrap justify-center gap-3 m-5 ">
35+
<h2 className="mt-2 text-primary md:hidden">All contracts</h2>
36+
<h1 className="hidden md:block md:mt-16">All contracts</h1>
37+
</div>
38+
<div className="flex flex-row justify-center gap-4 m-8">
39+
<InfoBadge
40+
title="Total Contract Classes"
41+
isLoading={loadingAmountContracts}
42+
error={errorAmountContracts}
43+
data={totalAmountOfContracts}
44+
/>
45+
<InfoBadge
46+
title="Total Contract Classes last 24h"
47+
isLoading={loadingAmountContracts24h}
48+
error={errorAmountContracts24h}
49+
data={totalAmountOfContracts24h}
50+
/>
51+
</div>
52+
53+
<div className="flex flex-col gap-4 md:flex-row ">
54+
<TableBadge
55+
title="Total Contract Instances"
56+
isLoading={isLoadingClasses}
57+
error={errorClasses}
58+
>
59+
{classesData && (
60+
<ContractClassesTable contracts={mapContractClasses(classesData)} />
61+
)}
62+
</TableBadge>
63+
64+
<TableBadge
65+
title="Total Contract Instances"
66+
isLoading={isLoadingInstances}
67+
error={errorInstances}
68+
>
69+
{instancesData && (
70+
<ContractInstancesTable
71+
contracts={mapContractInstances(instancesData)}
72+
/>
73+
)}
74+
</TableBadge>
75+
</div>
76+
</div>
77+
);
78+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
ChicmozL2ContractClassRegisteredEvent,
3+
ChicmozL2ContractInstanceDeluxe,
4+
} from "@chicmoz-pkg/types";
5+
import { contractClassSchema } from "~/components/contracts/classes/schema";
6+
import { contractInstanceSchema } from "~/components/contracts/instances/schema";
7+
8+
export const mapContractClasses = (
9+
classesData: ChicmozL2ContractClassRegisteredEvent[],
10+
) => {
11+
return classesData.map((contractClass) =>
12+
contractClassSchema.parse({
13+
blockHash: contractClass.blockHash,
14+
contractClassId: contractClass.contractClassId,
15+
version: contractClass.version,
16+
artifactHash: contractClass.artifactHash,
17+
privateFunctionsRoot: contractClass.privateFunctionsRoot,
18+
}),
19+
);
20+
};
21+
22+
export const mapContractInstances = (
23+
instancesData: ChicmozL2ContractInstanceDeluxe[],
24+
) => {
25+
return instancesData.map((contractInstance) =>
26+
contractInstanceSchema.parse({
27+
address: contractInstance.address,
28+
blockHash: contractInstance.blockHash,
29+
blockHeight: contractInstance.blockHeight,
30+
version: contractInstance.version,
31+
contractClassId: contractInstance.contractClassId,
32+
publicKeysHash: contractInstance.publicKeysHash,
33+
deployer: contractInstance.deployer,
34+
}),
35+
);
36+
};

0 commit comments

Comments
 (0)