Files
nym/explorer-nextjs/src/components/nymNodePageComponents/NodeRewardsCard.tsx
T
Yana Matrosova 9e4e8a9b2b Yana/pending staking events (#5400)
* Add pending events to stake table

* Add additional tanstack refetch on user stake/unstake/redeem rewards

* refactor repeated fetch functions

* clean up fetching functions

* refactor & clean up

* Add epoch waiting message on epoch change delay

* fine tune epoch change

* clean up

* refactor imports

* Add transaction hash to successful redeem rewards InfoModal

* fix epoch time check and mobile header

* Fix Loading modal width on mobile

* fix epoch logic

* clean up

* clean up logs

* add waiting for epoch to start to landing page

* clean up

* Add refetch of all queries on epoch change

* Finalise state change on epoch change

* clean up

* fix build

* Fix NodesTable mobile view

* Fix stake table mobile view

* fix typo

* Fix blog articles height

* Add loading skeletons to landing page cards

* clean up

* Add skeletons to cards

* Add skeletons, and loading/error refetch on wallet balnce

* clean up

* Add active stakers card

* clean up

* change NGM to mixnet

* Add TVL to Tokenomics card

* Add last total stake to Stake Card

* clean up

* Fix stake sorting function in Stake Table

* Add wrap of identity key and address to Basic Info Card

* Add counter to epoch time on staking page

* clean up

* update epoch labels

* Add circular loading on Toggle Button

* Update Toggle button loading functionality

* Add skeletons to account cards

* Add search functionality on Enter

* clean up

* DOMpurify node name and description

* Add column with id and identity key, wrap names to 2 lines

* Set width of column headers to 110px

* fix pending events for delegations

* Fix Stake button proppagation

* Add full country name to tooltips

* Take out connect wallet from mobile menu toggle

* finetune epoch change intervals

* Add error text to Magic Search

* fix build

* Add react-markdown for Blog articles

* fix graph's width and Table column headings

* fix Magic Search loading

* Fix grid on account page

* fix account card address width

* Fix permanent loading spinner on ToggleButton

* clean up URL's, fix copy address on the Basic Card

* replace mintscan with ping, open tx link on new page

* Take out toggle button if no node bonded by address

* Set fixed column width on tables

* Add not-found page to account, when no node bonded

* Add full country name to tables and node profile card

* clean up

* Table fixes

* Fix sorting in Delegations table Node page

* clean up

* Fix line chart view

* refactor epoch progress bar

* remove unused imports

* remove tanstack delclaration module

* create epoch data provider

* remove logic from togglebutton component

* use epoch provider in components

* invalidateQueries should be awaited

* tidy up QualityIndicatorsCard component formatting

* fix infinite loop in epoch provider

---------

Co-authored-by: Yana <yanok87@users.noreply.github.com>
Co-authored-by: fmtabbara <fmtabbara@hotmail.co.uk>
2025-02-27 19:11:50 +02:00

129 lines
3.3 KiB
TypeScript

"use client";
import { Skeleton, Typography } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { fetchEpochRewards, fetchNodeInfo } from "../../app/api";
import type { RewardingDetails } from "../../app/api/types";
import ExplorerCard from "../cards/ExplorerCard";
import ExplorerListItem from "../list/ListItem";
interface INodeRewardsCardProps {
id: number; // Node ID
}
export const NodeRewardsCard = ({ id }: INodeRewardsCardProps) => {
// Fetch epoch rewards
const {
data: epochRewardsData,
isLoading: isEpochLoading,
isError: isEpochError,
} = useQuery({
queryKey: ["epochRewards"],
queryFn: fetchEpochRewards,
});
// Fetch node information
const {
data: nodeInfo,
isLoading: isNodeLoading,
isError: isNodeError,
} = useQuery({
queryKey: ["nodeInfo", id],
queryFn: () => fetchNodeInfo(id),
});
if (isEpochLoading || isNodeLoading) {
return (
<ExplorerCard
label="Node rewards (last epoch/hour)"
sx={{ height: "100%" }}
>
<Skeleton variant="text" height={50} />
<Skeleton variant="text" height={50} />
<Skeleton variant="text" height={50} />
<Skeleton variant="text" height={50} />
</ExplorerCard>
);
}
if (isEpochError || isNodeError || !nodeInfo || !epochRewardsData) {
return (
<ExplorerCard
label="Node rewards (last epoch/hour)"
sx={{ height: "100%" }}
>
<Typography variant="h3" sx={{ color: "pine.950" }}>
Failed to load node data.
</Typography>
</ExplorerCard>
);
}
// Extract reward details
const rewardDetails: RewardingDetails = nodeInfo.rewarding_details;
// Calculated data
const operatorRewards = Number(rewardDetails.operator) / 1_000_000;
const operatorRewardsFormated = `${operatorRewards} NYM`;
const profitMarginPercent =
Number(rewardDetails.cost_params.profit_margin_percent) * 100;
const profitMarginPercentFormated = `${profitMarginPercent}%`;
const operatingCosts =
Number(rewardDetails.cost_params.interval_operating_cost.amount) /
1_000_000;
const operatingCostsFormated = `${operatingCosts.toString()} NYM`;
const getNodeSaturationPoint = (
totalStake: number,
stakeSaturationPoint: string,
): string => {
const saturation = Number.parseFloat(stakeSaturationPoint);
if (Number.isNaN(saturation) || saturation <= 0) {
throw new Error("Invalid stake saturation point provided");
}
const ratio = (totalStake / saturation) * 100;
return `${ratio.toFixed()}%`;
};
const nodeSaturationPoint = getNodeSaturationPoint(
nodeInfo.total_stake,
epochRewardsData.interval.stake_saturation_point,
);
return (
<ExplorerCard
label="Node rewards (last epoch/hour)"
sx={{ height: "100%" }}
>
<ExplorerListItem
row
divider
label="Operator rew."
value={operatorRewardsFormated}
/>
<ExplorerListItem
row
divider
label="Profit margin rew."
value={profitMarginPercentFormated}
/>
<ExplorerListItem
row
divider
label="Operating cost"
value={operatingCostsFormated}
/>
<ExplorerListItem
row
label="Node stake saturation"
value={nodeSaturationPoint}
/>
</ExplorerCard>
);
};