Refactor Node page to accept identity_key in params

This commit is contained in:
Yana
2025-03-26 17:34:01 +01:00
parent df453158d6
commit 8ff96b11c9
12 changed files with 770 additions and 377 deletions
@@ -15,8 +15,6 @@ export default async function Account({
try {
const address = (await params).address;
return (
<ContentLayout>
<Grid container columnSpacing={5} rowSpacing={5}>
@@ -17,8 +17,10 @@ export default async function NymNode({
params: Promise<{ id: string }>; // node_id or identity_key
}) {
try {
const paramsId = (await params).id;
const id = Number(paramsId);
const paramId = (await params).id;
const id = Number(paramId);
return (
<ContentLayout>
@@ -26,7 +28,7 @@ export default async function NymNode({
<Grid size={12}>
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
<SectionHeading title="Nym Node Details" />
<NodePageButtonGroup paramId={id.toString()} />
<NodePageButtonGroup paramId={paramId} />
</Box>
</Grid>
<Grid
@@ -35,7 +37,7 @@ export default async function NymNode({
md: 4,
}}
>
<NodeProfileCard id={id} />
<NodeProfileCard paramId={paramId} />
</Grid>
<Grid
size={{
@@ -43,7 +45,7 @@ export default async function NymNode({
md: 4,
}}
>
<BasicInfoCard id={id} />
<BasicInfoCard paramId={paramId} />
</Grid>
<Grid
size={{
@@ -51,7 +53,7 @@ export default async function NymNode({
md: 4,
}}
>
<NodeRoleCard id={id} />
<NodeRoleCard paramId={paramId} />
</Grid>
<Grid
size={{
@@ -59,7 +61,7 @@ export default async function NymNode({
md: 6,
}}
>
<NodeParametersCard id={id} />
<NodeParametersCard paramId={paramId} />
</Grid>
<Grid
size={{
@@ -67,14 +69,14 @@ export default async function NymNode({
md: 6,
}}
>
<NodeDataCard id={id} />
<NodeDataCard paramId={paramId} />
</Grid>
<Grid
size={{
xs: 12,
}}
>
<NodeDelegationsCard id={id} />
<NodeDelegationsCard paramId={paramId} />
</Grid>
{/*
<Grid
-10
View File
@@ -53,16 +53,6 @@ export const fetchGatewayStatus = async (
return response.json();
};
// export const fetchNodeIdByIdentityKey = async (
// identity_key: string,
// ): Promise<number> => {
// const nodes = await fetchObservatoryNodes();
// const node = nodes?.find((node) => node.identity_key === identity_key);
// return node?.node_id || 0;
// };
export const fetchNodeDelegations = async (
id: number,
): Promise<NodeRewardDetails[]> => {
@@ -7,12 +7,15 @@ import { formatBigNum } from "../../utils/formatBigNumbers";
import ExplorerCard from "../cards/ExplorerCard";
import CopyToClipboard from "../copyToClipboard/CopyToClipboard";
import ExplorerListItem from "../list/ListItem";
import { IObservatoryNode } from "@/app/api/types";
interface IBasicInfoCardProps {
id: number;
}
type Props = {
paramId: string;
};
export const BasicInfoCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
export const BasicInfoCard = ({ id }: IBasicInfoCardProps) => {
const {
data: nymNodes,
isLoading,
@@ -50,7 +53,14 @@ export const BasicInfoCard = ({ id }: IBasicInfoCardProps) => {
);
}
const nodeInfo = nymNodes.find((node) => node.node_id === id);
// get node info based on wether it's dentity_key or node_id
if (paramId.length > 10) {
nodeInfo = nymNodes.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes.find((node) => node.node_id === Number(paramId));
}
if (!nodeInfo) return null;
@@ -9,6 +9,8 @@ import {
import { useRouter } from "next/navigation";
import { useMemo } from "react";
import type { NodeRewardDetails } from "../../app/api/types";
import { useQuery } from "@tanstack/react-query";
import { fetchNodeDelegations } from "@/app/api";
const ColumnHeading = ({
children,
@@ -27,13 +29,30 @@ const getNymsFormated = (unyms: string) => {
return balance.toFixed();
};
const DelegationsTable = ({
delegations,
}: {
delegations: NodeRewardDetails[];
}) => {
type Props = {
id: number;
};
const DelegationsTable = ({ id }: Props) => {
const router = useRouter();
const {
data: delegations = [],
isLoading,
isError,
} = useQuery({
queryKey: ["nodeDelegations", id],
queryFn: () => fetchNodeDelegations(id),
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
if (isError) return null;
const columns: MRT_ColumnDef<NodeRewardDetails>[] = useMemo(
() => [
{
@@ -6,12 +6,15 @@ import { Skeleton, Typography } from "@mui/material";
import { format } from "date-fns";
import ExplorerCard from "../cards/ExplorerCard";
import ExplorerListItem from "../list/ListItem";
import { IObservatoryNode } from "@/app/api/types";
interface INodeMetricsCardProps {
id: number; // Node ID
}
type Props = {
paramId: string;
};
export const NodeDataCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
export const NodeDataCard = ({ id }: INodeMetricsCardProps) => {
const {
data: epochRewardsData,
isLoading: isEpochLoading,
@@ -61,7 +64,14 @@ export const NodeDataCard = ({ id }: INodeMetricsCardProps) => {
);
}
const nodeInfo = nymNodes.find((node) => node.node_id === id);
// get node info based on wether it's dentity_key or node_id
if (paramId.length > 10) {
nodeInfo = nymNodes.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes.find((node) => node.node_id === Number(paramId));
}
if (!nodeInfo) return null;
@@ -1,30 +1,45 @@
"use client";
import { fetchNodeDelegations } from "@/app/api";
import { fetchObservatoryNodes } from "@/app/api";
import { Skeleton, Typography } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import ExplorerCard from "../cards/ExplorerCard";
import DelegationsTable from "./DelegationsTable";
import { IObservatoryNode } from "@/app/api/types";
interface NodeDelegationsCardProps {
id: number; // Node ID
}
type Props = {
paramId: string;
};
const NodeDelegationsCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
const NodeDelegationsCard = ({ id }: NodeDelegationsCardProps) => {
const {
data: delegations = [],
isLoading,
data: nymNodes,
isError,
isLoading
} = useQuery({
queryKey: ["nodeDelegations", id],
queryFn: () => fetchNodeDelegations(id),
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
if (paramId.length > 10) {
nodeInfo = nymNodes?.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes?.find((node) => node.node_id === Number(paramId));
}
if (!nodeInfo) return null;
const id = nodeInfo.node_id
if (isLoading) {
return (
<ExplorerCard label="Delegations" sx={{ height: "100%" }}>
@@ -48,7 +63,7 @@ const NodeDelegationsCard = ({ id }: NodeDelegationsCardProps) => {
return (
<ExplorerCard label="Delegations" sx={{ height: "100%" }}>
<DelegationsTable delegations={delegations} />
<DelegationsTable id={id} />
</ExplorerCard>
);
};
@@ -3,26 +3,15 @@
import { useQuery } from "@tanstack/react-query";
import { fetchObservatoryNodes } from "@/app/api";
import ExplorerButtonGroup from "@/components/toggleButton/ToggleButton";
import { IObservatoryNode } from "@/app/api/types";
type Props = {
paramId: string;
};
// const resolveNodeId = async (paramId: string) => {
// if (paramId.length > 10) {
// return await fetchNodeIdByIdentityKey(paramId);
// }
// return Number(paramId);
// };
// const fetchResolvedNodeInfo = async (paramId: string) => {
// const id = await resolveNodeId(paramId);
// const node = await fetchNodeInfo(id);
// return { node, id };
// };
export default function NodePageButtonGroup({ paramId }: Props) {
const id = Number(paramId)
let nodeInfo: IObservatoryNode | undefined
const {
data: nymNodes,
isError,
@@ -38,7 +27,16 @@ export default function NodePageButtonGroup({ paramId }: Props) {
if (!nymNodes || isError) return null;
const nodeInfo = nymNodes.find((node) => node.node_id === id);
// get node info based on wether it's dentity_key or node_id
if (paramId.length > 10) {
nodeInfo = nymNodes.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes.find((node) => node.node_id === Number(paramId));
}
if (!nodeInfo) return null;
@@ -4,15 +4,17 @@ import { formatBigNum } from "@/utils/formatBigNumbers";
import { Skeleton, Typography } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { fetchEpochRewards, fetchObservatoryNodes } from "../../app/api";
import type { RewardingDetails } from "../../app/api/types";
import type { IObservatoryNode, RewardingDetails } from "../../app/api/types";
import ExplorerCard from "../cards/ExplorerCard";
import ExplorerListItem from "../list/ListItem";
interface INodeParametersCardProps {
id: number; // Node ID
}
type Props = {
paramId: string;
};
export const NodeParametersCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
export const NodeParametersCard = ({ id }: INodeParametersCardProps) => {
// Fetch epoch rewards
const {
data: epochRewardsData,
@@ -62,9 +64,17 @@ export const NodeParametersCard = ({ id }: INodeParametersCardProps) => {
</ExplorerCard>
);
}
const nodeInfo = nymNodes.find((node) => node.node_id === id);
// get node info based on wether it's dentity_key or node_id
if (paramId.length > 10) {
nodeInfo = nymNodes.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes.find((node) => node.node_id === Number(paramId));
}
if (!nodeInfo) return null;
const totalStake = formatBigNum(Number(nodeInfo.total_stake) / 1_000_000);
const totalStakeFormatted = `${totalStake} NYM`;
@@ -17,12 +17,15 @@ import InfoModal, { type InfoModalProps } from "../modal/InfoModal";
import StakeModal from "../staking/StakeModal";
import { fee } from "../staking/schemas";
import ConnectWallet from "../wallet/ConnectWallet";
import { IObservatoryNode } from "@/app/api/types";
interface INodeProfileCardProps {
id: number; // Node ID
}
type Props = {
paramId: string;
};
export const NodeProfileCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
export const NodeProfileCard = ({ id }: INodeProfileCardProps) => {
const { isWalletConnected } = useChain(COSMOS_KIT_USE_CHAIN);
const { nymClient } = useNymClient();
const [infoModalProps, setInfoModalProps] = useState<InfoModalProps>({
@@ -49,7 +52,15 @@ export const NodeProfileCard = ({ id }: INodeProfileCardProps) => {
});
const nodeInfo = nymNodes?.find((node) => node.node_id === id);
// get node info based on wether it's dentity_key or node_id
if (paramId.length > 10) {
nodeInfo = nymNodes?.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes?.find((node) => node.node_id === Number(paramId));
}
const handleOnSelectStake = useCallback(() => {
if (!nodeInfo) return;
@@ -80,6 +91,15 @@ export const NodeProfileCard = ({ id }: INodeProfileCardProps) => {
}
}, [isWalletConnected, nodeInfo]);
if (isLoadingNymNodes) {
return (
<ExplorerCard label="Nym Node" sx={{ height: "100%" }}>
<Skeleton variant="rectangular" height={80} width={80} />
<Skeleton variant="text" />
<Skeleton variant="text" height={200} />
</ExplorerCard>
);
}
if (isError || !nymNodes) {
return (
<ExplorerCard label="Nym Node" sx={{ height: "100%" }}>
@@ -90,15 +110,6 @@ export const NodeProfileCard = ({ id }: INodeProfileCardProps) => {
);
}
if (isLoadingNymNodes) {
return (
<ExplorerCard label="Nym Node" sx={{ height: "100%" }}>
<Skeleton variant="rectangular" height={80} width={80} />
<Skeleton variant="text" />
<Skeleton variant="text" height={200} />
</ExplorerCard>
);
}
const handleStakeOnNode = async ({
nodeId,
@@ -7,14 +7,14 @@ import {
fetchGatewayStatus,
fetchObservatoryNodes,
} from "../../app/api";
import type { LastProbeResult, NodeDescription } from "../../app/api/types";
import type { IObservatoryNode, LastProbeResult, NodeDescription } from "../../app/api/types";
import ExplorerCard from "../cards/ExplorerCard";
import ExplorerListItem from "../list/ListItem";
import StarRating from "../starRating/StarRating";
interface INodeRoleCardProps {
id: number; // Node ID
}
type Props = {
paramId: string;
};
type NodeDescriptionNotNull = NonNullable<NodeDescription>;
type DeclaredRoleKey = keyof NodeDescriptionNotNull["declared_role"];
@@ -143,7 +143,9 @@ function calculateWireguardPerformance(probeResult: LastProbeResult): number {
}
}
export const NodeRoleCard = ({ id }: INodeRoleCardProps) => {
export const NodeRoleCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
// Fetch node info
const {
data: nymNodes,
@@ -171,8 +173,13 @@ export const NodeRoleCard = ({ id }: INodeRoleCardProps) => {
});
const nodeInfo = nymNodes?.find((node) => node.node_id === id);
// Extract node roles once `nodeInfo` is available
if (paramId.length > 10) {
nodeInfo = nymNodes?.find((node) => node.identity_key === paramId);
} else {
nodeInfo = nymNodes?.find((node) => node.node_id === Number(paramId));
} // Extract node roles once `nodeInfo` is available
const nodeRoles = nodeInfo
? getNodeRoles(nodeInfo.description.declared_role)
: [];
+611 -288
View File
File diff suppressed because it is too large Load Diff