get node details from unstable endpoint + layout updates
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { IBondInfo, INodeDescription } from "@/app/api";
|
||||
import { NYM_NODE_BONDED, NYM_NODE_DESCRIPTION } from "@/app/api/urls";
|
||||
import type NodeData from "@/app/api/types";
|
||||
import { NYM_NODES } from "@/app/api/urls";
|
||||
import { ContentLayout } from "@/components/contentLayout/ContentLayout";
|
||||
import SectionHeading from "@/components/headings/SectionHeading";
|
||||
import { BasicInfoCard } from "@/components/nymNodePageComponents/BasicInfoCard";
|
||||
@@ -13,11 +13,11 @@ import { Box, Grid2 } from "@mui/material";
|
||||
export default async function NymNode({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
params: Promise<{ id: string; account?: string }>;
|
||||
}) {
|
||||
const id = Number((await params).id);
|
||||
|
||||
const descriptionData = await fetch(NYM_NODE_DESCRIPTION, {
|
||||
const response = await fetch(NYM_NODES, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
@@ -25,70 +25,86 @@ export default async function NymNode({
|
||||
next: { revalidate: 60 },
|
||||
// refresh event list cache at given interval
|
||||
});
|
||||
const nymNodesDescription = await descriptionData.json();
|
||||
|
||||
const bondedData = await fetch(NYM_NODE_BONDED, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
next: { revalidate: 60 },
|
||||
// refresh event list cache at given interval
|
||||
});
|
||||
const nymbondedData = await bondedData.json();
|
||||
const nymNodes: NodeData[] = await response.json();
|
||||
|
||||
if (!bondedData || !nymNodesDescription) {
|
||||
if (!nymNodes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodeBondInfo = nymbondedData.data.filter(
|
||||
(item: IBondInfo) => item.bond_information.node_id === id,
|
||||
);
|
||||
const nymNode = nymNodes.find((node) => node.node_id === id);
|
||||
|
||||
const nodeDescriptionInfo = nymNodesDescription.data.filter(
|
||||
(item: INodeDescription) => item.node_id === id,
|
||||
);
|
||||
if (!nymNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ContentLayout>
|
||||
<Grid2 container columnSpacing={5} rowSpacing={5}>
|
||||
<Grid2 size={6}>
|
||||
<SectionHeading title="Nym Node Details" />
|
||||
</Grid2>
|
||||
<Grid2 size={6} justifyContent="flex-end">
|
||||
<Box sx={{ display: "flex", justifyContent: "end" }}>
|
||||
<Grid2 size={12}>
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
|
||||
<SectionHeading title="Nym Node Details" />
|
||||
<ExplorerButtonGroup
|
||||
options={[
|
||||
{ label: "Nym Node", isSelected: true, link: "/nym-node/1" },
|
||||
{
|
||||
label: "Account",
|
||||
isSelected: false,
|
||||
link: "/account/1",
|
||||
link: `/account/${nymNode.bond_information.owner}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Box>
|
||||
</Grid2>
|
||||
<Grid2 size={4}>
|
||||
<Grid2
|
||||
size={{
|
||||
xs: 12,
|
||||
md: 4,
|
||||
}}
|
||||
>
|
||||
<NodeProfileCard
|
||||
bondInfo={nodeBondInfo[0]}
|
||||
nodeDescription={nodeDescriptionInfo[0]}
|
||||
bondInfo={nymNode.bond_information}
|
||||
nodeDescription={nymNode.description}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={4}>
|
||||
<Grid2
|
||||
size={{
|
||||
xs: 12,
|
||||
md: 4,
|
||||
}}
|
||||
>
|
||||
<BasicInfoCard
|
||||
bondInfo={nodeBondInfo[0]}
|
||||
nodeDescription={nodeDescriptionInfo[0]}
|
||||
bondInfo={nymNode.bond_information}
|
||||
nodeDescription={nymNode.description}
|
||||
rewardDetails={nymNode.rewarding_details}
|
||||
/>
|
||||
</Grid2>
|
||||
<Grid2 size={4}>
|
||||
<QualityIndicatorsCard nodeDescription={nodeDescriptionInfo[0]} />
|
||||
<Grid2
|
||||
size={{
|
||||
xs: 12,
|
||||
md: 4,
|
||||
}}
|
||||
>
|
||||
<QualityIndicatorsCard nodeDescription={nymNode.description} />
|
||||
</Grid2>
|
||||
<Grid2 size={6}>
|
||||
<NodeRewardsCard bondInfo={nodeBondInfo[0]} />
|
||||
<Grid2
|
||||
size={{
|
||||
xs: 12,
|
||||
md: 6,
|
||||
}}
|
||||
>
|
||||
<NodeRewardsCard rewardDetails={nymNode.rewarding_details} />
|
||||
</Grid2>
|
||||
<Grid2 size={6}>
|
||||
<NodeMetricsCard nodeDescription={nodeDescriptionInfo[0]} />
|
||||
<Grid2
|
||||
size={{
|
||||
xs: 12,
|
||||
md: 6,
|
||||
}}
|
||||
>
|
||||
<NodeMetricsCard
|
||||
nodeDescription={nymNode.description}
|
||||
nodeId={nymNode.bond_information.node_id}
|
||||
/>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</ContentLayout>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { IBondInfo, INodeDescription } from "@/app/api";
|
||||
import type {
|
||||
BondInformation,
|
||||
NodeDescription,
|
||||
RewardingDetails,
|
||||
} from "@/app/api/types";
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { format } from "date-fns";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
@@ -6,19 +10,20 @@ import CopyToClipboard from "../copyToClipboard/CopyToClipboard";
|
||||
import ExplorerListItem from "../list/ListItem";
|
||||
|
||||
interface IBasicInfoCardProps {
|
||||
bondInfo: IBondInfo;
|
||||
nodeDescription: INodeDescription;
|
||||
bondInfo: BondInformation;
|
||||
nodeDescription: NodeDescription;
|
||||
rewardDetails: RewardingDetails;
|
||||
}
|
||||
|
||||
export const BasicInfoCard = (props: IBasicInfoCardProps) => {
|
||||
const { bondInfo, nodeDescription } = props;
|
||||
const { bondInfo, nodeDescription, rewardDetails } = props;
|
||||
|
||||
const timeBonded = format(
|
||||
new Date(nodeDescription.description.build_information.build_timestamp),
|
||||
new Date(nodeDescription.build_information.build_timestamp),
|
||||
"dd/MM/yyyy",
|
||||
);
|
||||
|
||||
const selfBond = Number(bondInfo.rewarding_details.unit_delegation) / 1000000;
|
||||
const selfBond = Number(rewardDetails.unit_delegation) / 1_000_000;
|
||||
const selfBondFormated = `${selfBond} NYM`;
|
||||
return (
|
||||
<ExplorerCard label="Basic info">
|
||||
@@ -34,10 +39,8 @@ export const BasicInfoCard = (props: IBasicInfoCardProps) => {
|
||||
justifyContent="space-between"
|
||||
width="100%"
|
||||
>
|
||||
<Typography variant="body4">
|
||||
{bondInfo.bond_information.owner}
|
||||
</Typography>
|
||||
<CopyToClipboard text={bondInfo.bond_information.owner} />
|
||||
<Typography variant="body4">{bondInfo.owner}</Typography>
|
||||
<CopyToClipboard text={bondInfo.owner} />
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
@@ -53,11 +56,9 @@ export const BasicInfoCard = (props: IBasicInfoCardProps) => {
|
||||
width="100%"
|
||||
>
|
||||
<Typography variant="body4">
|
||||
{bondInfo.bond_information.node.identity_key}
|
||||
{bondInfo.node.identity_key}
|
||||
</Typography>
|
||||
<CopyToClipboard
|
||||
text={bondInfo.bond_information.node.identity_key}
|
||||
/>
|
||||
<CopyToClipboard text={bondInfo.node.identity_key} />
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
@@ -66,7 +67,7 @@ export const BasicInfoCard = (props: IBasicInfoCardProps) => {
|
||||
row
|
||||
divider
|
||||
label="Nr. of stakes"
|
||||
value={bondInfo.rewarding_details.unique_delegations.toString()}
|
||||
value={rewardDetails.unique_delegations.toString()}
|
||||
/>
|
||||
<ExplorerListItem row label="Self bonded" value={selfBondFormated} />
|
||||
</Stack>
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
import type { INodeDescription } from "@/app/api";
|
||||
import type { NodeDescription } from "@/app/api/types";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
import ExplorerListItem from "../list/ListItem";
|
||||
|
||||
interface INodeMetricsCardProps {
|
||||
nodeDescription: INodeDescription;
|
||||
nodeDescription: NodeDescription;
|
||||
nodeId: number;
|
||||
}
|
||||
|
||||
export const NodeMetricsCard = (props: INodeMetricsCardProps) => {
|
||||
const { nodeDescription } = props;
|
||||
const { nodeDescription, nodeId } = props;
|
||||
return (
|
||||
<ExplorerCard label="Nym node metrics" sx={{ height: "100%" }}>
|
||||
<ExplorerListItem
|
||||
row
|
||||
divider
|
||||
label="Node ID."
|
||||
value={nodeDescription.node_id.toString()}
|
||||
value={nodeId.toString()}
|
||||
/>
|
||||
<ExplorerListItem
|
||||
row
|
||||
divider
|
||||
label="Host"
|
||||
value={nodeDescription.description.host_information.ip_address.toString()}
|
||||
value={nodeDescription.host_information.ip_address.toString()}
|
||||
/>
|
||||
<ExplorerListItem
|
||||
row
|
||||
divider
|
||||
label="Version"
|
||||
value={nodeDescription.description.build_information.build_version}
|
||||
value={nodeDescription.build_information.build_version}
|
||||
/>
|
||||
<ExplorerListItem row label="Active set Prob." value="High" />
|
||||
</ExplorerCard>
|
||||
|
||||
@@ -1,30 +1,23 @@
|
||||
"use client";
|
||||
import type { IBondInfo, INodeDescription } from "@/app/api";
|
||||
import type { BondInformation, NodeDescription } from "@/app/api/types";
|
||||
import { Box, Button, Stack, Typography } from "@mui/material";
|
||||
import { RandomAvatar } from "react-random-avatars";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
import CountryFlag from "../countryFlag/CountryFlag";
|
||||
|
||||
interface INodeProfileCardProps {
|
||||
bondInfo: IBondInfo;
|
||||
nodeDescription: INodeDescription;
|
||||
bondInfo: BondInformation;
|
||||
nodeDescription: NodeDescription;
|
||||
}
|
||||
|
||||
export const NodeProfileCard = (props: INodeProfileCardProps) => {
|
||||
const { bondInfo, nodeDescription } = props;
|
||||
|
||||
console.log("nodeDescription :>> ", nodeDescription);
|
||||
console.log("bondInfo :>> ", bondInfo);
|
||||
|
||||
return (
|
||||
<ExplorerCard label="Nym Node" sx={{ height: "100%" }}>
|
||||
<Stack gap={1}>
|
||||
<Box display={"flex"} justifyContent={"flex-start"}>
|
||||
<RandomAvatar
|
||||
name={nodeDescription.description.address}
|
||||
size={80}
|
||||
square
|
||||
/>
|
||||
<RandomAvatar name={bondInfo.node.identity_key} size={80} square />
|
||||
</Box>
|
||||
<Typography
|
||||
variant="h3"
|
||||
@@ -34,9 +27,7 @@ export const NodeProfileCard = (props: INodeProfileCardProps) => {
|
||||
{"Moniker"}
|
||||
</Typography>
|
||||
<CountryFlag
|
||||
countryCode={
|
||||
nodeDescription.description.auxiliary_details.location || ""
|
||||
}
|
||||
countryCode={nodeDescription.auxiliary_details.location || ""}
|
||||
/>
|
||||
<Typography variant="body4" sx={{ color: "pine.950" }}>
|
||||
Team of professional validators with best digital solutions. Please
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
import type { IBondInfo } from "@/app/api";
|
||||
import type { RewardingDetails } from "@/app/api/types";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
import ExplorerListItem from "../list/ListItem";
|
||||
|
||||
interface INodeRewardsCardProps {
|
||||
bondInfo: IBondInfo;
|
||||
rewardDetails: RewardingDetails;
|
||||
}
|
||||
|
||||
export const NodeRewardsCard = (props: INodeRewardsCardProps) => {
|
||||
const { bondInfo } = props;
|
||||
const { rewardDetails } = props;
|
||||
|
||||
const totalRewards =
|
||||
Number(bondInfo.rewarding_details.total_unit_reward) / 1000000;
|
||||
const totalRewards = Number(rewardDetails.total_unit_reward) / 1000000;
|
||||
const totalRewardsFormated = `${totalRewards} NYM`;
|
||||
|
||||
const operatorRewards = Number(bondInfo.rewarding_details.operator) / 1000000;
|
||||
const operatorRewards = Number(rewardDetails.operator) / 1000000;
|
||||
const operatorRewardsFormated = `${operatorRewards} NYM`;
|
||||
|
||||
const stakerRewards = Number(bondInfo.rewarding_details.delegates) / 1000000;
|
||||
const stakerRewards = Number(rewardDetails.delegates) / 1000000;
|
||||
const stakerRewardsFormated = `${stakerRewards} NYM`;
|
||||
|
||||
const profitMarginPercent =
|
||||
Number(bondInfo.rewarding_details.cost_params.profit_margin_percent) * 100;
|
||||
Number(rewardDetails.cost_params.profit_margin_percent) * 100;
|
||||
|
||||
const profitMarginPercentFormated = `${profitMarginPercent}%`;
|
||||
|
||||
const operatingCosts =
|
||||
Number(
|
||||
bondInfo.rewarding_details.cost_params.interval_operating_cost.amount,
|
||||
) / 1000000;
|
||||
Number(rewardDetails.cost_params.interval_operating_cost.amount) / 1000000;
|
||||
const operatingCostsFormated = `${operatingCosts.toString()} NYM`;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { INodeDescription } from "@/app/api";
|
||||
import type { NodeDescription } from "@/app/api/types";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
import ExplorerListItem from "../list/ListItem";
|
||||
import StarRating from "../starRating/StarRating";
|
||||
|
||||
interface IQualityIndicatorsCardProps {
|
||||
nodeDescription: INodeDescription;
|
||||
nodeDescription: NodeDescription;
|
||||
}
|
||||
|
||||
interface IDeclaredRoles {
|
||||
@@ -39,7 +39,7 @@ export const QualityIndicatorsCard = (props: IQualityIndicatorsCardProps) => {
|
||||
const { nodeDescription } = props;
|
||||
|
||||
const nodeRoles = getNodeRoles({
|
||||
declared_role: nodeDescription.description.declared_role,
|
||||
declared_role: nodeDescription.declared_role,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user