add fixes

This commit is contained in:
Yana
2025-04-10 11:02:20 +03:00
parent 5179f38ad2
commit bdfbfde463
51 changed files with 677 additions and 414 deletions
+2 -2
View File
@@ -16,8 +16,8 @@ const nextConfig: NextConfig = {
basePath: false,
permanent: true,
},
]
}
];
},
};
export default nextConfig;
+1 -1
View File
@@ -62,4 +62,4 @@
"lefthook": "^1.8.5",
"typescript": "^5"
}
}
}
@@ -1,11 +1,10 @@
import AccountPageButtonGroup from "@/components/accountPageComponents/AccountPageButtonGroup";
import { Box, Typography } from "@mui/material";
import Grid from "@mui/material/Grid2";
import { AccountBalancesCard } from "../../../../components/accountPageComponents/AccountBalancesCard";
import { AccountInfoCard } from "../../../../components/accountPageComponents/AccountInfoCard";
import { ContentLayout } from "../../../../components/contentLayout/ContentLayout";
import SectionHeading from "../../../../components/headings/SectionHeading";
import AccountPageButtonGroup from "@/components/accountPageComponents/AccountPageButtonGroup";
export default async function Account({
params,
@@ -19,7 +19,6 @@ export default async function NymNode({
try {
const paramId = (await params).id;
return (
<ContentLayout>
<Grid container columnSpacing={5} rowSpacing={5}>
@@ -70,13 +70,13 @@ export default async function BlogPage({
<Typography key={author} variant="subtitle3">
{author}
</Typography>
)
),
)}
</Box>
<time dateTime={blogArticle?.attributes?.date.toString()}>
{format(
new Date(blogArticle?.attributes?.date),
"MMMM dd, yyyy"
"MMMM dd, yyyy",
)}
</time>
</Typography>
-2
View File
@@ -192,8 +192,6 @@ export const fetchAccountBalance = async (
return data;
};
export const fetchObservatoryNodes = async (): Promise<IObservatoryNode[]> => {
const allNodes: IObservatoryNode[] = [];
let page = 1;
-1
View File
@@ -1,4 +1,3 @@
export const CURRENT_EPOCH =
"https://validator.nymtech.net/api/v1/epoch/current";
export const CURRENT_EPOCH_REWARDS =
+4 -4
View File
@@ -3,8 +3,8 @@ import { QueryClient } from "@tanstack/react-query";
let queryClient: QueryClient | null = null;
export function getQueryClient() {
if (!queryClient) {
queryClient = new QueryClient();
}
return queryClient;
if (!queryClient) {
queryClient = new QueryClient();
}
return queryClient;
}
@@ -126,9 +126,9 @@ export const AccountBalancesCard = (props: IAccountBalancesCardProps) => {
const spendableAllocation =
accountInfo.balances.length > 0
? getAllocation(
Number(accountInfo.balances[0].amount),
Number(accountInfo.total_value.amount),
)
Number(accountInfo.balances[0].amount),
Number(accountInfo.total_value.amount),
)
: 0;
const delegationsNYM = getNymsFormated(
@@ -12,8 +12,8 @@ import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import useMediaQuery from "@mui/material/useMediaQuery";
import { useTheme } from "@mui/material/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
import * as React from "react";
import { TABLET_WIDTH } from "../../app/constants";
import { MultiSegmentProgressBar } from "../progressBars/MultiSegmentProgressBar";
@@ -1,54 +1,47 @@
'use client';
"use client";
import { useQuery } from "@tanstack/react-query";
import { fetchObservatoryNodes } from "@/app/api";
import ExplorerButtonGroup from "@/components/toggleButton/ToggleButton";
import { useQuery } from "@tanstack/react-query";
type Props = {
address: string;
address: string;
};
export default function AccountPageButtonGroup({ address }: Props) {
const {
data: nymNodes,
isError,
} = useQuery({
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
const { data: nymNodes, isError } = useQuery({
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
if (!nymNodes || isError) return null;
if (!nymNodes || isError) return null;
const nymNode = nymNodes.find(
(node) => node.bonding_address === address,
const nymNode = nymNodes.find((node) => node.bonding_address === address);
if (!nymNode) return null;
if (nymNode.bonding_address)
return (
<ExplorerButtonGroup
onPage="Account"
options={[
{
label: "Nym Node",
isSelected: false,
link: nymNode
? `/nym-node/${nymNode.node_id}`
: `/account/${address}/not-found`,
},
{
label: "Account",
isSelected: true,
link: `/account/${address}`,
},
]}
/>
);
if (!nymNode) return null;
if (nymNode.bonding_address) return (
<ExplorerButtonGroup
onPage="Account"
options={[
{
label: "Nym Node",
isSelected: false,
link: nymNode
? `/nym-node/${nymNode.node_id}`
: `/account/${address}/not-found`,
},
{
label: "Account",
isSelected: true,
link: `/account/${address}`,
},
]}
/>
);
}
@@ -1,9 +1,9 @@
import fs from "node:fs/promises";
import path from "node:path";
import { type IconName, icons } from "@/utils/getIconByName";
import Grid from "@mui/material/Grid2";
import ExplorerHeroCard from "../cards/ExplorerHeroCard";
import type { BlogArticleWithLink } from "./types";
import { icons, IconName } from "@/utils/getIconByName";
// TODO: Articles should be sorted by date
@@ -28,21 +28,21 @@ const BlogArticlesCards = async ({
...blogArticle,
link: `/onboarding/${filename.replace(".json", "")}`,
};
})
}),
);
// --- End Data Fetching ---
const limitedOrFilteredBlogArticles = (
blogArticles: BlogArticleWithLink[],
limit?: number,
ids?: number[]
ids?: number[],
): BlogArticleWithLink[] => {
let filteredArticles = blogArticles;
// Filter by IDs if provided
if (ids && ids.length > 0) {
filteredArticles = filteredArticles.filter((article) =>
ids.includes(article.id)
ids.includes(article.id),
);
}
@@ -2,8 +2,8 @@ import {
Card,
CardContent,
CardHeader,
useTheme,
type SxProps,
useTheme,
} from "@mui/material";
const cardStyles = {
@@ -1,6 +1,6 @@
"use client";
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
// import { useMainContext } from "@/context";
export const SocialIcon = ({ channel }: { channel: string }): JSX.Element => {
@@ -4,8 +4,8 @@ import { Link } from "../../components/muiLink";
import { Wrapper } from "../../components/wrapper";
import ConnectWallet from "../wallet/ConnectWallet";
import HeaderItem from "./HeaderItem";
import MENU_DATA from "./menuItems";
import { DarkLightSwitchDesktop } from "./Switch";
import MENU_DATA from "./menuItems";
export const DesktopHeader = () => {
return (
@@ -52,7 +52,6 @@ export const DesktopHeader = () => {
</Box>
<ConnectWallet size="small" />
<DarkLightSwitchDesktop defaultChecked />
</Wrapper>
<Divider variant="fullWidth" sx={{ width: "100%" }} />
</Box>
@@ -1,14 +1,14 @@
"use client";
import { Close as CloseIcon, Menu as MenuIcon } from "@mui/icons-material";
import { Box, Drawer, IconButton, Typography } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { useState } from "react";
import { Link } from "../../components/muiLink";
import { Wrapper } from "../../components/wrapper";
import NymLogo from "../icons/NymLogo";
import ConnectWallet from "../wallet/ConnectWallet";
import MENU_DATA from "./menuItems";
import { DarkLightSwitchDesktop } from "./Switch";
import { useTheme } from "@mui/material/styles";
import MENU_DATA from "./menuItems";
export const MobileHeader = () => {
const [drawerOpen, setDrawerOpen] = useState(false);
+4 -4
View File
@@ -1,10 +1,10 @@
"use client";
import * as React from "react";
import { styled } from "@mui/material/styles";
import Switch from "@mui/material/Switch";
import { Button } from "@mui/material";
import { PaletteMode } from "@mui/material";
import type { PaletteMode } from "@mui/material";
import Switch from "@mui/material/Switch";
import { styled } from "@mui/material/styles";
import { useLocalStorage } from "@uidotdev/usehooks";
import * as React from "react";
export const DarkLightSwitch = styled(Switch)(({ theme }) => ({
width: 55,
@@ -19,8 +19,7 @@ const MENU_DATA: MenuItem[] = [
id: 3,
title: "Onboarding",
url: "/onboarding",
}
},
];
export default MENU_DATA;
@@ -3,12 +3,7 @@ import Image from "next/image";
import { icons } from "@/utils/getIconByName";
const ArrowUpRight = () => (
<Image
src={icons.arrowUpRight}
alt="Arrow Up Right"
width={32}
height={32}
/>
<Image src={icons.arrowUpRight} alt="Arrow Up Right" width={32} height={32} />
);
export default ArrowUpRight;
+2 -7
View File
@@ -1,14 +1,9 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const ChevronMenu = () => {
return (
<Image
src={icons.chevronMenu}
alt="Chevron Menu"
width={24}
height={24}
/>
<Image src={icons.chevronMenu} alt="Chevron Menu" width={24} height={24} />
);
};
@@ -1,6 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const CopyFile = ({ className }: { className?: string }) => (
<Image
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const CopyFile = ({ className }: { className?: string }) => (
<Image
+1 -1
View File
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const Cross = () => (
<Image src={icons.cross} alt="cross" width={12.5} height={12.5} />
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const CrossDark = () => (
<Image src={icons.crossDark} alt="cross" width={12.5} height={12.5} />
+1 -1
View File
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
export const Elips = () => (
<Image src={icons.elips} alt="Elips" width={20} height={20} />
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
export const ElipseDark = () => (
<Image src={icons.elipseDark} alt="Elips" width={20} height={20} />
+1 -1
View File
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
const Gateway = () => {
return (
+2 -2
View File
@@ -1,8 +1,8 @@
"use client";
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import { PaletteMode } from "@mui/material";
import type { PaletteMode } from "@mui/material";
import { useLocalStorage } from "@uidotdev/usehooks";
import Image from "next/image";
const NymLogo = () => {
const [mode] = useLocalStorage<PaletteMode>("mode", "dark");
+1 -1
View File
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
export const Token = () => {
return <Image src={icons.token} alt="Token" width={20} height={20} />;
@@ -1,5 +1,5 @@
import Image from "next/image";
import { icons } from "@/utils/getIconByName";
import Image from "next/image";
export const TokenDark = () => {
return <Image src={icons.tokenDark} alt="Token" width={20} height={20} />;
@@ -37,7 +37,7 @@ export const CurrentEpochCard = () => {
const updateState = useCallback((data: NonNullable<EpochResponseData>) => {
const { startTime, endTime } = getStartEndTime(
data.current_epoch_start,
data.current_epoch_end
data.current_epoch_end,
);
const progress = calulateProgress(data.current_epoch_end);
@@ -46,7 +46,7 @@ export const StakersNumberCard = () => {
const getActiveStakersNumber = (nodes: IObservatoryNode[]): number => {
return nodes.reduce(
(sum, node) => sum + node.rewarding_details.unique_delegations,
0
0,
);
};
const allStakers = getActiveStakersNumber(nymNodes);
@@ -20,7 +20,6 @@ export const TokenomicsCard = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
const {
@@ -34,7 +33,6 @@ export const TokenomicsCard = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
const {
@@ -48,7 +46,6 @@ export const TokenomicsCard = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
if (isLoading || isEpochLoading || isStakingLoading) {
@@ -100,7 +100,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
{ nodeId },
fee,
"Delegation from Nym Explorer V2",
uNymFunds
uNymFunds,
);
setSelectedNodeForStaking(undefined);
setInfoModalProps({
@@ -129,7 +129,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
}
setIsLoading(false);
},
[nymClient, handleRefetch]
[nymClient, handleRefetch],
);
const handleOnSelectStake = useCallback(
@@ -158,7 +158,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
identityKey: node.identity_key,
});
},
[isWalletConnected]
[isWalletConnected],
);
const columns: MRT_ColumnDef<MappedNymNode>[] = useMemo(
@@ -303,7 +303,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
enableSorting: false,
},
],
[isWalletConnected, handleOnSelectStake, favorites]
[isWalletConnected, handleOnSelectStake, favorites],
);
const table = useMaterialReactTable({
columns,
@@ -70,7 +70,6 @@ const NodeTableWithAction = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Use React Query to fetch Nym nodes
@@ -85,7 +84,6 @@ const NodeTableWithAction = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Handle loading state
@@ -1,5 +1,6 @@
"use client";
import type { IObservatoryNode } from "@/app/api/types";
import { Skeleton, Stack, Typography } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { fetchObservatoryNodes } from "../../app/api";
@@ -7,14 +8,13 @@ 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";
type Props = {
paramId: string;
};
export const BasicInfoCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
const {
data: nymNodes,
@@ -29,7 +29,6 @@ export const BasicInfoCard = ({ paramId }: Props) => {
refetchOnMount: false,
});
if (isLoading) {
return (
<ExplorerCard label="Basic info">
@@ -53,11 +52,10 @@ export const BasicInfoCard = ({ paramId }: Props) => {
);
}
// get node info based on wether it's dentity_key or node_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));
}
@@ -1,6 +1,8 @@
"use client";
import { fetchNodeDelegations } from "@/app/api";
import { Stack, Typography, useTheme } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import {
type MRT_ColumnDef,
MaterialReactTable,
@@ -9,8 +11,6 @@ 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,
@@ -86,7 +86,7 @@ const DelegationsTable = ({ id }: Props) => {
),
},
],
[]
[],
);
const table = useMaterialReactTable({
columns,
@@ -1,19 +1,19 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { fetchEpochRewards, fetchObservatoryNodes } from "../../app/api";
import type { IObservatoryNode } from "@/app/api/types";
import { Skeleton, Typography } from "@mui/material";
import { useQuery } from "@tanstack/react-query";
import { format } from "date-fns";
import { fetchEpochRewards, fetchObservatoryNodes } from "../../app/api";
import ExplorerCard from "../cards/ExplorerCard";
import ExplorerListItem from "../list/ListItem";
import { IObservatoryNode } from "@/app/api/types";
type Props = {
paramId: string;
};
export const NodeDataCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
const {
data: epochRewardsData,
@@ -26,7 +26,6 @@ export const NodeDataCard = ({ paramId }: Props) => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Fetch node information
@@ -64,11 +63,10 @@ export const NodeDataCard = ({ paramId }: Props) => {
);
}
// get node info based on wether it's dentity_key or node_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));
}
@@ -1,23 +1,23 @@
"use client";
import { fetchObservatoryNodes } from "@/app/api";
import { fetchObservatoryNodes } from "@/app/api";
import type { IObservatoryNode } from "@/app/api/types";
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";
type Props = {
paramId: string;
};
const NodeDelegationsCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
const {
data: nymNodes,
isError,
isLoading
isLoading,
} = useQuery({
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
@@ -27,18 +27,15 @@ const NodeDelegationsCard = ({ paramId }: Props) => {
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
const id = nodeInfo.node_id;
if (isLoading) {
return (
@@ -1,62 +1,54 @@
'use client';
"use client";
import { useQuery } from "@tanstack/react-query";
import { fetchObservatoryNodes } from "@/app/api";
import type { IObservatoryNode } from "@/app/api/types";
import ExplorerButtonGroup from "@/components/toggleButton/ToggleButton";
import { IObservatoryNode } from "@/app/api/types";
import { useQuery } from "@tanstack/react-query";
type Props = {
paramId: string;
paramId: string;
};
export default function NodePageButtonGroup({ paramId }: Props) {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
const {
data: nymNodes,
isError,
} = useQuery({
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
const { data: nymNodes, isError } = useQuery({
queryKey: ["nymNodes"],
queryFn: fetchObservatoryNodes,
staleTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
});
if (!nymNodes || isError) return null;
if (!nymNodes || isError) return null;
// 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));
}
// get node info based on wether it's dentity_key or node_id
if (!nodeInfo) return null;
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;
if (nodeInfo.bonding_address) return (
<ExplorerButtonGroup
onPage="Nym Node"
options={[
{
label: "Nym Node",
isSelected: true,
link: `/nym-node/${nodeInfo.node_id}`,
},
{
label: "Account",
isSelected: false,
link: `/account/${nodeInfo.bonding_address}`,
},
]}
/>
if (nodeInfo.bonding_address)
return (
<ExplorerButtonGroup
onPage="Nym Node"
options={[
{
label: "Nym Node",
isSelected: true,
link: `/nym-node/${nodeInfo.node_id}`,
},
{
label: "Account",
isSelected: false,
link: `/account/${nodeInfo.bonding_address}`,
},
]}
/>
);
}
@@ -13,7 +13,7 @@ type Props = {
};
export const NodeParametersCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
// Fetch epoch rewards
const {
@@ -27,7 +27,6 @@ export const NodeParametersCard = ({ paramId }: Props) => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Fetch node information
@@ -64,11 +63,10 @@ export const NodeParametersCard = ({ paramId }: Props) => {
</ExplorerCard>
);
}
// get node info based on wether it's dentity_key or node_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));
}
@@ -1,5 +1,6 @@
"use client";
import type { IObservatoryNode } from "@/app/api/types";
import { useChain } from "@cosmos-kit/react";
import {
Box,
@@ -24,7 +25,6 @@ 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";
type Props = {
paramId: string;
@@ -137,7 +137,7 @@ export const NodeProfileCard = ({ paramId }: Props) => {
{ nodeId },
fee,
"Delegation from Nym Explorer V2",
uNymFunds
uNymFunds,
);
setSelectedNodeForStaking(undefined);
setInfoModalProps({
@@ -165,11 +165,11 @@ export const NodeProfileCard = ({ paramId }: Props) => {
if (!nodeInfo) return null;
const cleanMoniker = DOMPurify.sanitize(
nodeInfo?.self_description.moniker
nodeInfo?.self_description.moniker,
).replace(/&amp;/g, "&");
const cleanDescription = DOMPurify.sanitize(
nodeInfo?.self_description.details
nodeInfo?.self_description.details,
).replace(/&amp;/g, "&");
// get full country name
@@ -212,7 +212,7 @@ export const NodeProfileCard = ({ paramId }: Props) => {
<CountryFlag
countryCode={nodeInfo.description.auxiliary_details.location}
countryName={countryName(
nodeInfo.description.auxiliary_details.location
nodeInfo.description.auxiliary_details.location,
)}
/>
</Box>
@@ -7,7 +7,11 @@ import {
fetchGatewayStatus,
fetchObservatoryNodes,
} from "../../app/api";
import type { IObservatoryNode, 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";
@@ -144,7 +148,7 @@ function calculateWireguardPerformance(probeResult: LastProbeResult): number {
}
export const NodeRoleCard = ({ paramId }: Props) => {
let nodeInfo: IObservatoryNode | undefined
let nodeInfo: IObservatoryNode | undefined;
// Fetch node info
const {
@@ -170,16 +174,13 @@ export const NodeRoleCard = ({ paramId }: Props) => {
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));
} // Extract node roles once `nodeInfo` is available
} // Extract node roles once `nodeInfo` is available
const nodeRoles = nodeInfo
? getNodeRoles(nodeInfo.description.declared_role)
: [];
@@ -189,7 +190,6 @@ export const NodeRoleCard = ({ paramId }: Props) => {
["Entry Node", "Exit IPR Node", "Exit NR Node"].includes(role),
);
// Fetch gateway status only if `shouldFetchGatewayStatus` is true
const { data: gatewayStatus } = useQuery({
queryKey: ["gatewayStatus", nodeInfo?.identity_key],
@@ -220,7 +220,6 @@ export const NodeRoleCard = ({ paramId }: Props) => {
);
}
const NodeRoles = nodeRoles.map((role) => (
<Stack key={role} direction="row" gap={1}>
<Chip key={role} label={role} size="small" />
@@ -229,7 +228,6 @@ export const NodeRoleCard = ({ paramId }: Props) => {
if (!nodeInfo) return null;
const qualityOfServiceStars = nodeInfo?.uptime
? calculateQualityOfServiceStars(nodeInfo.uptime)
: gatewayStatus
@@ -16,7 +16,6 @@ const EpochProgressBar = ({
endTime,
progress,
}: IDynamicProgressBarProps) => {
return (
<Box sx={{ width: "100%" }}>
<ProgressBar value={progress} color="secondary" />
@@ -82,7 +82,7 @@ const ColumnHeading = ({
const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
const { nymClient, address, nymQueryClient } = useNymClient();
const [delegations, setDelegations] = useState<DelegationWithNodeDetails[]>(
[]
[],
);
const [isDataLoading, setIsLoading] = useState(false);
const [infoModalProps, setInfoModalProps] = useState<InfoModalProps>({
@@ -121,13 +121,13 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
const combineDelegationsWithNodeAndPendingEvents = (
delegations: Delegation[],
nodes: MappedNymNode[],
pendingEvents: PendingEvent[] | undefined
pendingEvents: PendingEvent[] | undefined,
) => {
// Combine delegations with node details
const delegationsWithNodeDetails = delegations.map((delegation) => {
const node = nodes.find((node) => node.nodeId === delegation.node_id);
const pendingEvent = pendingEvents?.find(
(event) => event?.mixId === delegation.node_id
(event) => event?.mixId === delegation.node_id,
);
return {
@@ -145,7 +145,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
!delegationsWithNodeDetails.find(
(item) =>
item.node?.nodeId === e.mixId ||
item.delegation.node_id === e.mixId
item.delegation.node_id === e.mixId,
)
) {
delegationsWithNodeDetails.push({
@@ -185,7 +185,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
combineDelegationsWithNodeAndPendingEvents(
delegations,
nodes,
pendingEvents
pendingEvents,
);
setDelegations(delegationsWithNodeDetails);
@@ -206,7 +206,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
{ nodeId },
fee,
"Delegation from Nym Explorer V2",
uNymFunds
uNymFunds,
);
setSelectedNodeForStaking(undefined);
@@ -235,7 +235,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
}
setIsLoading(false);
},
[nymClient, handleRefetch]
[nymClient, handleRefetch],
);
const handleOnSelectStake = useCallback(
@@ -266,7 +266,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
});
}
},
[isWalletConnected]
[isWalletConnected],
);
const handleUnstake = useCallback(
@@ -281,7 +281,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
nodeId,
},
fee,
`Explorer V2: Unstaking node ${nodeId}`
`Explorer V2: Unstaking node ${nodeId}`,
);
setIsLoading(false);
await handleRefetch();
@@ -306,7 +306,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
setIsLoading(false);
}
},
[address, nymClient, handleRefetch]
[address, nymClient, handleRefetch],
);
const handleActionSelect = useCallback(
@@ -322,7 +322,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
break;
}
},
[handleUnstake, handleOnSelectStake]
[handleUnstake, handleOnSelectStake],
);
const getTooltipTitle = useCallback(
@@ -333,13 +333,13 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
if (pending?.kind === "delegate") {
return `You have a delegation pending worth ${formatBigNum(
+pending.amount.amount / 1_000_000
+pending.amount.amount / 1_000_000,
)} NYM`;
}
return undefined;
},
[] // Add dependencies if necessary
[], // Add dependencies if necessary
);
const columns: MRT_ColumnDef<DelegationWithNodeDetails>[] = useMemo(
@@ -418,10 +418,10 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
sortingFn: (rowA, rowB) => {
const stakeA = Number.parseFloat(
rowA.original.delegation.amount.amount
rowA.original.delegation.amount.amount,
);
const stakeB = Number.parseFloat(
rowB.original.delegation.amount.amount
rowB.original.delegation.amount.amount,
);
return stakeA - stakeB;
},
@@ -466,10 +466,10 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
),
sortingFn: (rowA, rowB) => {
const isFavoriteA = favorites.includes(
rowA.original.node?.owner || "-"
rowA.original.node?.owner || "-",
);
const isFavoriteB = favorites.includes(
rowB.original.node?.owner || "-"
rowB.original.node?.owner || "-",
);
// Sort favorites first
@@ -509,7 +509,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
handleActionSelect(
action,
row.original.delegation?.node_id,
row.original.node?.identity_key || undefined
row.original.node?.identity_key || undefined,
);
}}
/>
@@ -519,7 +519,7 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
},
},
],
[handleActionSelect, favorites, getTooltipTitle]
[handleActionSelect, favorites, getTooltipTitle],
);
const table = useMaterialReactTable({
@@ -698,4 +698,3 @@ const StakeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
};
export default StakeTable;
@@ -68,7 +68,6 @@ const StakeTableWithAction = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Use React Query to fetch Nym nodes
@@ -83,7 +82,6 @@ const StakeTableWithAction = () => {
refetchOnWindowFocus: false, // Prevents unnecessary refetching
refetchOnReconnect: false,
refetchOnMount: false,
});
// Handle loading state
@@ -1,12 +1,12 @@
"use client";
import { useCallback, useState } from "react";
import { useChain } from "@cosmos-kit/react";
import { GasPrice } from "@cosmjs/stargate";
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { GasPrice } from "@cosmjs/stargate";
import { useChain } from "@cosmos-kit/react";
import { Button, Stack } from "@mui/material";
import type { Delegation } from "@nymproject/contract-clients/Mixnet.types";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useState } from "react";
import { fetchTotalStakerRewards } from "../../app/api";
import type { NodeRewardDetails } from "../../app/api/types";
import { COSMOS_KIT_USE_CHAIN, NYM_MIXNET_CONTRACT } from "../../config";
@@ -15,7 +15,6 @@ import Loading from "../loading";
import InfoModal, { type InfoModalProps } from "../modal/InfoModal";
import RedeemRewardsModal from "../redeemRewards/RedeemRewardsModal";
// Fetch delegations
const fetchDelegations = async (
address: string,
@@ -35,7 +34,8 @@ const SubHeaderRowActions = () => {
});
const { address, nymClient } = useNymClient();
const { getSigningCosmWasmClient, getOfflineSigner } = useChain(COSMOS_KIT_USE_CHAIN);
const { getSigningCosmWasmClient, getOfflineSigner } =
useChain(COSMOS_KIT_USE_CHAIN);
const queryClient = useQueryClient();
@@ -83,9 +83,9 @@ const SubHeaderRowActions = () => {
const gasPrice = GasPrice.fromString("0.025unym");
const client = await SigningCosmWasmClient.connectWithSigner(
"https://rpc.nymtech.net/",
"https://rpc.nymtech.net/",
signer,
{ gasPrice }
{ gasPrice },
);
const messages = delegations.map((delegation: NodeRewardDetails) => ({
@@ -135,7 +135,7 @@ const SubHeaderRowActions = () => {
delegations,
getSigningCosmWasmClient,
handleRefetch,
getOfflineSigner
getOfflineSigner,
]);
const handleRedeemRewardsButtonClick = () => {
@@ -1,11 +1,11 @@
"use client";
import { CssBaseline, PaletteMode } from "@mui/material";
import { CssBaseline, type PaletteMode } from "@mui/material";
import { ThemeProvider as MUIThemeProvider } from "@mui/material";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v15-appRouter";
import { lightTheme, darkTheme } from "../theme/theme";
import { useLocalStorage } from "@uidotdev/usehooks";
import { useEffect, useState } from "react";
import { darkTheme, lightTheme } from "../theme/theme";
const ClientThemeProvider = ({ children }: { children: React.ReactNode }) => {
const [isMounted, setIsMounted] = useState(false);
+1 -1
View File
@@ -3,7 +3,7 @@
import { getQueryClient } from "@/app/react-query";
import { QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { type ReactNode } from "react";
import type { ReactNode } from "react";
interface QueryProviderProps {
children: ReactNode;
+19 -19
View File
@@ -1,32 +1,32 @@
import type { StaticImageData } from "next/image";
import nymLogo from "@/../public/icons/nym-logo.svg";
import nymLogoWhite from "@/../public/icons/nym-logo-white.svg";
import token from "@/../public/icons/token.svg";
import tokenDark from "@/../public/icons/token-dark.svg";
import gateway from "@/../public/icons/gateway.svg";
import elips from "@/../public/icons/elips.svg";
import elipseDark from "@/../public/icons/elipse-dark.svg";
import cross from "@/../public/icons/cross.svg";
import crossDark from "@/../public/icons/cross-dark.svg";
import copyFile from "@/../public/icons/copy-file.svg";
import copyFileDark from "@/../public/icons/copy-file-dark.svg";
import arrowUpRight from "@/../public/icons/arrow-up-right.svg";
import arrow from "@/../public/icons/arrow-up-right.svg";
import chevronMenu from "@/../public/icons/chevronMenu.svg";
import copyFileDark from "@/../public/icons/copy-file-dark.svg";
import copyFile from "@/../public/icons/copy-file.svg";
import crossDark from "@/../public/icons/cross-dark.svg";
import cross from "@/../public/icons/cross.svg";
import discord from "@/../public/icons/discord.svg";
import document from "@/../public/icons/document.svg";
import download from "@/../public/icons/download.svg";
import discord from "@/../public/icons/discord.svg";
import elips from "@/../public/icons/elips.svg";
import elipseDark from "@/../public/icons/elipse-dark.svg";
import explorerCardDark from "@/../public/icons/explorer-card-dark.svg";
import explorerCard from "@/../public/icons/explorer-card.svg";
import gatewayDark from "@/../public/icons/gateway-dark.svg";
import gateway from "@/../public/icons/gateway.svg";
import github from "@/../public/icons/github.svg";
import nymLogoWhite from "@/../public/icons/nym-logo-white.svg";
import nymLogo from "@/../public/icons/nym-logo.svg";
import stakeCardDark from "@/../public/icons/stake-card-dark.svg";
import stakeCard from "@/../public/icons/stake-card.svg";
import telegram from "@/../public/icons/telegram.svg";
import tokenDark from "@/../public/icons/token-dark.svg";
import token from "@/../public/icons/token.svg";
import twitter from "@/../public/icons/twitter.svg";
import youtube from "@/../public/icons/youtube.svg";
import youTubeInverted from "@/../public/icons/youtubeInverted.svg";
import arrowUpRight from "@/../public/icons/arrow-up-right.svg";
import arrow from "@/../public/icons/arrow-up-right.svg";
import explorerCard from "@/../public/icons/explorer-card.svg";
import stakeCard from "@/../public/icons/stake-card.svg";
import stakeCardDark from "@/../public/icons/stake-card-dark.svg";
import explorerCardDark from "@/../public/icons/explorer-card-dark.svg";
import gatewayDark from "@/../public/icons/gateway-dark.svg";
export type IconName =
| "nymLogo"
+477 -161
View File
File diff suppressed because it is too large Load Diff