Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

internal: one component for OptionButtons #283

Merged
merged 6 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions services/explorer-ui/src/components/option-buttons/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { CustomTooltip } from "~/components/custom-tooltip";
import {
Button,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
Separator,
} from "~/components/ui";

export type OptionItem = {
id: string;
label: string;
};

export type OptionItems = OptionItem[];

type ExtractOptionId<T extends OptionItems> = T[number]["id"];

type OptionButtonProps<T extends OptionItems> = {
options: T;
availableOptions: Record<string, boolean>; // TODO: this should work: Record<ExtractOptionId<T>, boolean>
onOptionSelect: (option: ExtractOptionId<T>) => void;
selectedItem: ExtractOptionId<T>;
};

const withAvailableTooltip = (
isAvailable: boolean,
key: number,
children: React.ReactNode
) => {
if (!isAvailable) {
return (
<CustomTooltip key={key} content="Not available">
{children}
</CustomTooltip>
);
}

return <div key={key}>{children}</div>;
};

export const OptionButtons = <T extends OptionItems>({
options,
availableOptions,
onOptionSelect,
selectedItem,
}: OptionButtonProps<T>) => {
return (
<>
<div className="hidden lg:flex flex-row gap-4 mb-4 justify-center">
{options.map((option, key) => {
const isAvailable = availableOptions[option.id];
return withAvailableTooltip(
isAvailable,
key,
<div className="flex flex-col justify-center items-center gap-1">
<Button
key={key}
onClick={() => onOptionSelect(option.id)}
disabled={!isAvailable}
variant="default"
className="hover:bg-slate-500 border border-input"
>
{option.label}
</Button>
{selectedItem === option.id && (
<Separator className="h-0.5 bg-gray-700 w-1/2" />
)}
</div>
);
})}
</div>
<div className="mb-1 mt-4 lg:hidden">
<Select onValueChange={onOptionSelect} value={selectedItem}>
<SelectTrigger className="h-8 w-3/5 bg-primary text-white">
<SelectValue placeholder={selectedItem} />
</SelectTrigger>
<SelectContent>
{
options.map((option, key) => (
<SelectItem
key={key}
disabled={!availableOptions[option.id]}
value={option.id}
>
{option.label}
</SelectItem>
))
}
</SelectContent>
</Select>
</div>
</>
);
};
19 changes: 19 additions & 0 deletions services/explorer-ui/src/pages/block-details/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { z } from "zod";

export type tabId = "txEffects" | "contracts";

export const tabIds = ["txEffects", "contracts"] as const;

export const tabIdSchema = z.enum(tabIds);
export type TabId = z.infer<typeof tabIdSchema>;

export const tabSchema = z.object({
id: tabIdSchema,
label: z.string(),
});
export type Tab = z.infer<typeof tabSchema>;

export const blockDetailsTabs: Tab[] = [
{ id: "txEffects", label: "Transaction effects" },
{ id: "contracts", label: "Contracts" },
];
35 changes: 21 additions & 14 deletions services/explorer-ui/src/pages/block-details/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { useParams } from "@tanstack/react-router";
import { type FC } from "react";
import { useState, type FC } from "react";
import { KeyValueDisplay } from "~/components/info-display/key-value-display";
import { OptionButtons } from "~/components/option-buttons";
import { TxEffectsTable } from "~/components/tx-effects/tx-effects-table";
import { Button } from "~/components/ui";
import {
useGetBlockByIdentifier,
useGetTxEffectsByBlockHeight,
useSubTitle,
} from "~/hooks";
import { blockDetailsTabs, type TabId } from "./constants";
import { getBlockDetails, getTxEffects } from "./util";

export const BlockDetails: FC = () => {
const { blockNumber } = useParams({
from: "/blocks/$blockNumber",
});
useSubTitle(`Block ${blockNumber}`);
const [selectedTab, setSelectedTab] = useState<TabId>("txEffects");
const onOptionSelect = (value: string) => {
setSelectedTab(value as TabId);
};
const {
data: latestBlock,
isLoading,
Expand All @@ -28,7 +33,6 @@ export const BlockDetails: FC = () => {
error: txEffectsError,
} = useGetTxEffectsByBlockHeight(height);

//TODO: Check for better solution
if (!latestBlock) return <div> No block hash</div>;

return (
Expand All @@ -37,19 +41,22 @@ export const BlockDetails: FC = () => {
<div>
<h2>Block Details </h2>
</div>
<div className="flex flex-col gap-4 mt-8">
<div className="flex flex-col gap-4 mt-8 pb-4">
<div className="bg-white rounded-lg shadow-md p-4">
<KeyValueDisplay data={getBlockDetails(latestBlock)} />
</div>
<div className="flex flex-row gap-4 w-10 mb-4">
<Button
variant={"default"}
className={"shadow-[0px_0px_1px_2px_rgba(0,0,0,1)]"}
>
<p>View TxEffects</p>
</Button>
</div>
<div className="rounded-lg shadow-lg">
</div>
<OptionButtons
options={blockDetailsTabs}
availableOptions={{
txEffects: !!blockTxEffects,
contracts: false, // TODO
}}
onOptionSelect={onOptionSelect}
selectedItem={selectedTab}
/>
<div className="bg-white rounded-lg shadow-md p-4">
{selectedTab === "txEffects" && (
<TxEffectsTable
txEffects={getTxEffects(blockTxEffects, latestBlock)}
isLoading={
Expand All @@ -59,7 +66,7 @@ export const BlockDetails: FC = () => {
}
error={error ?? txEffectsError}
/>
</div>
)}
</div>
</div>
</div>
Expand Down
14 changes: 8 additions & 6 deletions services/explorer-ui/src/pages/contract-class-details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useState, type FC } from "react";
import { ContractClassesTable } from "~/components/contracts/classes/table";
import { ContractInstancesTable } from "~/components/contracts/instances/table";
import { KeyValueDisplay } from "~/components/info-display/key-value-display";
import { OptionButtons } from "~/components/option-buttons";
import {
useContractClassPrivateFunctions,
useContractClassUnconstrainedFunctions,
Expand All @@ -12,15 +13,14 @@ import {
} from "~/hooks";
import { mapContractClasses, mapContractInstances } from "../contract/util";
import { contractClassTabs, type TabId } from "./constants";
import { OptionButtons } from "./tabs";
import { getContractClassKeyValueData } from "./util";

export const ContractClassDetails: FC = () => {
const [selectedTab, setSelectedTab] = useState<TabId>("contractVersions");
const { id, version } = useParams({
from: "/contracts/classes/$id/versions/$version",
});
useSubTitle(`Ctrct cls ${id}`);
const [selectedTab, setSelectedTab] = useState<TabId>("contractVersions");
const onOptionSelect = (value: string) => {
setSelectedTab(value as TabId);
};
Expand Down Expand Up @@ -48,11 +48,13 @@ export const ContractClassDetails: FC = () => {
privateFunctions:
!contractClassPrivateFunctionsHookRes.isLoading &&
!contractClassPrivateFunctionsHookRes.error &&
!!contractClassPrivateFunctionsHookRes.data,
!!contractClassPrivateFunctionsHookRes.data &&
!!contractClassPrivateFunctionsHookRes.data.length,
unconstrainedFunctions:
!contractClassUnconstrainedFunctionsHookRes.isLoading &&
!contractClassUnconstrainedFunctionsHookRes.error &&
!!contractClassUnconstrainedFunctionsHookRes.data,
!!contractClassUnconstrainedFunctionsHookRes.data &&
!!contractClassUnconstrainedFunctionsHookRes.data.length,
};

if (!id) return <div>No classId</div>;
Expand All @@ -77,8 +79,8 @@ export const ContractClassDetails: FC = () => {
</div>
</div>
<OptionButtons
availableData={isOptionAvailable}
requiredOptions={contractClassTabs}
options={contractClassTabs}
availableOptions={isOptionAvailable}
onOptionSelect={onOptionSelect}
selectedItem={selectedTab}
/>
Expand Down
94 changes: 0 additions & 94 deletions services/explorer-ui/src/pages/contract-class-details/tabs.tsx

This file was deleted.

Loading