Skip to content

Commit

Permalink
Merge pull request #5379 from nymtech/yana/frontend-fixes
Browse files Browse the repository at this point in the history
Yana/frontend fixes
  • Loading branch information
yanok87 authored Jan 23, 2025
2 parents f4a416c + 961a813 commit 50ac19a
Show file tree
Hide file tree
Showing 28 changed files with 769 additions and 227 deletions.
8 changes: 4 additions & 4 deletions explorer-nextjs/src/app/(pages)/account/[address]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CurrencyRates, IAccountBalancesInfo } from "@/app/api/types";
import type { IAccountBalancesInfo, NymTokenomics } from "@/app/api/types";
import type NodeData from "@/app/api/types";
import { NYM_ACCOUNT_ADDRESS, NYM_NODES, NYM_PRICES_API } from "@/app/api/urls";
import { AccountBalancesCard } from "@/components/accountPageComponents/AccountBalancesCard";
Expand Down Expand Up @@ -58,7 +58,7 @@ export default async function Account({
// refresh event list cache at given interval
});

const nymPriceData: CurrencyRates = await nymPrice.json();
const nymPriceData: NymTokenomics = await nymPrice.json();

return (
<ContentLayout>
Expand Down Expand Up @@ -92,15 +92,15 @@ export default async function Account({
<Grid size={8}>
<AccountBalancesCard
accountInfo={nymAccountBalancesData}
nymPrice={nymPriceData.usd}
nymPrice={nymPriceData.quotes.USD.price}
/>
</Grid>
</Grid>
<Grid container columnSpacing={5} rowSpacing={5}>
<Grid size={12}>
<SectionHeading title="Onboarding" />
</Grid>
<BlogArticlesCards limit={2} />
<BlogArticlesCards limit={4} />
</Grid>
</ContentLayout>
);
Expand Down
21 changes: 19 additions & 2 deletions explorer-nextjs/src/app/(pages)/nym-node/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { ExplorerData } from "@/app/api";
import type { IObservatoryNode } from "@/app/api/types";
import { DATA_OBSERVATORY_NODES_URL } from "@/app/api/urls";
import {
CURRENT_EPOCH_REWARDS,
DATA_OBSERVATORY_NODES_URL,
} from "@/app/api/urls";
import BlogArticlesCards from "@/components/blogs/BlogArticleCards";
import ExplorerCard from "@/components/cards/ExplorerCard";
import { ContentLayout } from "@/components/contentLayout/ContentLayout";
Expand All @@ -21,6 +25,15 @@ export default async function NymNode({
params: Promise<{ id: string }>;
}) {
try {
const epochRewards = await fetch(CURRENT_EPOCH_REWARDS, {
headers: {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
},
});
const epochRewardsData: ExplorerData["currentEpochRewardsData"] =
await epochRewards.json();

const id = Number((await params).id);

const observatoryResponse = await fetch(DATA_OBSERVATORY_NODES_URL, {
Expand Down Expand Up @@ -128,6 +141,7 @@ export default async function NymNode({
<NodeRewardsCard
rewardDetails={observatoryNymNode.rewarding_details}
nodeInfo={observatoryNymNode}
epochRewardsData={epochRewardsData}
/>
</Grid>
)}
Expand All @@ -138,7 +152,10 @@ export default async function NymNode({
md: 6,
}}
>
<NodeMetricsCard nodeInfo={observatoryNymNode} />
<NodeMetricsCard
nodeInfo={observatoryNymNode}
epochRewardsData={epochRewardsData}
/>
</Grid>
)}
{delegations && (
Expand Down
64 changes: 56 additions & 8 deletions explorer-nextjs/src/app/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,6 @@ type NodeData = {

export default NodeData;

export interface CurrencyRates {
btc: number;
chf: number;
eur: number;
timestamp: number;
usd: number;
}

// ACCOUNT BALANCES

export interface IRewardDetails {
Expand Down Expand Up @@ -365,3 +357,59 @@ export type GatewayStatus = {
};
};
};

type BalanceDetails = {
amount: number;
denom: string;
};

export type ObservatoryRewards = {
operator_commissions: BalanceDetails;
staking_rewards: BalanceDetails;
unlocked: BalanceDetails;
};

export type ObservatoryBalance = {
delegated: BalanceDetails;
locked: BalanceDetails;
rewards: ObservatoryRewards;
self_bonded: BalanceDetails;
spendable: BalanceDetails;
};

export type Quote = {
ath_date: string;
ath_price: number;
market_cap: number;
market_cap_change_24h: number;
percent_change_12h: number;
percent_change_15m: number;
percent_change_1h: number;
percent_change_1y: number;
percent_change_24h: number;
percent_change_30d: number;
percent_change_30m: number;
percent_change_6h: number;
percent_change_7d: number;
percent_from_price_ath: number;
price: number;
volume_24h: number;
volume_24h_change_24h: number;
};

export type Quotes = {
USD: Quote;
};

export type NymTokenomics = {
beta_value: number;
first_data_at: string;
id: string;
last_updated: string;
max_supply: number;
name: string;
quotes: Quotes;
rank: number;
symbol: string;
total_supply: number;
};
7 changes: 5 additions & 2 deletions explorer-nextjs/src/app/api/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ export const NYM_NODE_BONDED =
"https://validator.nymtech.net/api/v1/nym-nodes/bonded";
export const NYM_ACCOUNT_ADDRESS =
"https://explorer.nymtech.net/api/v1/tmp/unstable/account/";
export const NYM_PRICES_API =
"https://canary-nym-vpn-chain-payment-watcher.nymte.ch/v1/price/average";
export const NYM_PRICES_API = "https://api.nym.spectredao.net/api/v1/nym-price";
export const VALIDATOR_BASE_URL =
process.env.NEXT_PUBLIC_VALIDATOR_URL || "https://rpc.nymtech.net";
export const DATA_OBSERVATORY_NODES_URL =
"https://api.nym.spectredao.net/api/v1/nodes";
export const DATA_OBSERVATORY_DELEGATIONS_URL =
"https://api.nym.spectredao.net/api/v1/delegations";
export const DATA_OBSERVATORY_BALANCES_URL =
"https://api.nym.spectredao.net/api/v1/balances";
2 changes: 1 addition & 1 deletion explorer-nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default async function Home() {
<Grid size={12}>
<SectionHeading title="Onboarding" />
</Grid>
<BlogArticlesCards limit={2} />
<BlogArticlesCards limit={4} />
</Grid>
</ContentLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const AccountBalancesCard = (props: IAccountBalancesCardProps) => {
Number(accountInfo.total_value.amount),
nymPrice,
);

const spendableNYM = getNymsFormated(Number(accountInfo.balances[0].amount));
const spendableUSD = getPriceInUSD(
Number(accountInfo.balances[0].amount),
Expand Down
4 changes: 2 additions & 2 deletions explorer-nextjs/src/components/blogs/BlogArticleCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const BlogArticlesCards = async ({ limit }: { limit?: number }) => {
.sort((a, b) => {
// sort by date
return (
new Date(a.attributes.date).getTime() -
new Date(b.attributes.date).getTime()
new Date(b.attributes.date).getTime() -
new Date(a.attributes.date).getTime()
);
})
.map((blogArticle) => {
Expand Down
2 changes: 1 addition & 1 deletion explorer-nextjs/src/components/countryFlag/CountryFlag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const CountryFlag = ({ countryCode, countryName }: ICountryFlag) => {
<Stack direction="row" gap={1}>
<Flag code={countryCode} width="19" />

<Typography variant="subtitle2" sx={{ color: "pine.950" }}>
<Typography variant="h6" sx={{ color: "pine.950" }}>
{countryName}
</Typography>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CurrencyRates } from "@/app/api/types";
import type { NymTokenomics } from "@/app/api/types";
import { NYM_PRICES_API } from "@/app/api/urls";
import { Box, Stack } from "@mui/material";
import ExplorerCard from "../cards/ExplorerCard";
Expand All @@ -15,8 +15,8 @@ export const TokenomicsCard = async () => {
// refresh event list cache at given interval
});

const nymPriceData: CurrencyRates = await nymPrice.json();
const nymPriceDataFormated = Number(nymPriceData.usd.toFixed(2));
const nymPriceData: NymTokenomics = await nymPrice.json();
const nymPriceDataFormated = Number(nymPriceData.quotes.USD.price.toFixed(2));

const titlePrice = {
price: nymPriceDataFormated,
Expand All @@ -25,9 +25,11 @@ export const TokenomicsCard = async () => {
// numberWentUp: true,
// },
};
const marketCap = nymPriceData.quotes.USD.market_cap;
const volume24H = nymPriceData.quotes.USD.volume_24h.toFixed(2);
const dataRows = [
{ key: "Market cap", value: "$ 1000000" },
{ key: "24H VOL", value: "$ 1000000" },
{ key: "Market cap", value: `$ ${marketCap}` },
{ key: "24H VOL", value: `$ ${volume24H}` },
];

return (
Expand Down
31 changes: 23 additions & 8 deletions explorer-nextjs/src/components/nodeTable/NodeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {

const columns: MRT_ColumnDef<MappedNymNode>[] = useMemo(
() => [
{
id: "name",
header: "",
Header: <ColumnHeading>Name</ColumnHeading>,
accessorKey: "name",
Cell: ({ row }) => (
<Stack spacing={1}>
<Typography variant="body4">{row.original.name || "-"}</Typography>
</Stack>
),
},
{
id: "node",
header: "",
Expand All @@ -143,7 +154,11 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
align: "center",
accessorKey: "qos",
Header: <ColumnHeading>Quality of Service</ColumnHeading>,
Cell: () => <Typography variant="body4">Unavailable</Typography>,
Cell: ({ row }) => (
<Typography variant="body4">
{row.original.qualityOfService}%
</Typography>
),
},
{
id: "location",
Expand All @@ -169,7 +184,11 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
header: "Stake saturation",
accessorKey: "stakeSaturation",
Header: <ColumnHeading>Stake saturation</ColumnHeading>,
Cell: () => <Typography variant="body4">Unavailable</Typography>,
Cell: ({ row }) => (
<Typography variant="body4">
{row.original.stakeSaturation}%
</Typography>
),
},
{
id: "profitMarginPercentage",
Expand Down Expand Up @@ -235,12 +254,8 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
},
sortingFns: {
Favorite: (rowA, rowB) => {
const isFavoriteA = favorites.includes(
rowA.original.bondInformation.owner,
);
const isFavoriteB = favorites.includes(
rowB.original.bondInformation.owner,
);
const isFavoriteA = favorites.includes(rowA.original.owner);
const isFavoriteB = favorites.includes(rowB.original.owner);

// Sort favorites first
if (isFavoriteA && !isFavoriteB) return -1;
Expand Down
64 changes: 60 additions & 4 deletions explorer-nextjs/src/components/nodeTable/NodeTableWithAction.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,65 @@
import getNymNodes from "@/actions/getNymNodes";
import type { ExplorerData } from "@/app/api";
import type { IObservatoryNode } from "@/app/api/types";
import { CURRENT_EPOCH_REWARDS } from "@/app/api/urls";
import NodeTable from "./NodeTable";

const mappedNymNodes = (nodes: IObservatoryNode[]) =>
async function fetchEpochRewards() {
try {
const response = await fetch(CURRENT_EPOCH_REWARDS, {
headers: {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
},
});

if (!response.ok) {
throw new Error(`Failed to fetch epoch rewards: ${response.statusText}`);
}

return await response.json();
} catch (error) {
console.error("Error fetching epoch rewards:", error);
throw new Error("Failed to fetch epoch rewards data");
}
}

function getNodeSaturationPoint(
totalStake: number,
stakeSaturationPoint: string,
): number {
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 Number(ratio.toFixed());
}

const mappedNymNodes = (
nodes: IObservatoryNode[],
epochRewardsData: ExplorerData["currentEpochRewardsData"],
) =>
nodes.map((node) => {
const nodeSaturationPoint = getNodeSaturationPoint(
node.total_stake,
epochRewardsData.interval.stake_saturation_point,
);

return {
name: node.self_description.moniker,
nodeId: node.node_id,
identity_key: node.identity_key,
countryCode: node.description.auxiliary_details.location || null,
countryName: node.description.auxiliary_details.location || null,
profitMarginPercentage:
+node.rewarding_details.cost_params.profit_margin_percent * 100,
owner: node.bonding_address,
stakeSaturation: nodeSaturationPoint,
qualityOfService: +node.uptime * 100,
};
});

Expand All @@ -20,12 +68,20 @@ export type MappedNymNode = MappedNymNodes[0];

const NodeTableWithAction = async () => {
try {
// Fetch the epoch rewards data
const epochRewardsData: ExplorerData["currentEpochRewardsData"] =
await fetchEpochRewards();

// Fetch the Nym nodes
const nodes = await getNymNodes();
const data = mappedNymNodes(nodes);

// Map the nodes with the rewards data
const data = mappedNymNodes(nodes, epochRewardsData);

return <NodeTable nodes={data} />;
} catch (error) {
console.error(error);
return [];
console.error("Error in NodeTableWithAction:", error);
return <div>Error loading data.</div>; // Render error fallback UI
}
};

Expand Down
Loading

0 comments on commit 50ac19a

Please sign in to comment.