fix build
This commit is contained in:
@@ -1,29 +1,29 @@
|
||||
import { countryCodeMap } from "@/assets/countryCodes";
|
||||
import { addSeconds } from "date-fns";
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import type {
|
||||
CountryDataResponse,
|
||||
CurrentEpochData,
|
||||
ExplorerData,
|
||||
GatewayStatus,
|
||||
IAccountBalancesInfo,
|
||||
IObservatoryNode,
|
||||
IPacketsAndStakingData,
|
||||
NodeRewardDetails,
|
||||
NS_NODE,
|
||||
NodeRewardDetails,
|
||||
NymTokenomics,
|
||||
ObservatoryBalance,
|
||||
CountryDataResponse,
|
||||
} from "./types";
|
||||
import {
|
||||
CURRENT_EPOCH,
|
||||
CURRENT_EPOCH_REWARDS,
|
||||
DATA_OBSERVATORY_BALANCES_URL,
|
||||
DATA_OBSERVATORY_NODES_URL,
|
||||
NS_API_NODES,
|
||||
NYM_ACCOUNT_ADDRESS,
|
||||
NYM_PRICES_API,
|
||||
OBSERVATORY_GATEWAYS_URL,
|
||||
NS_API_NODES,
|
||||
} from "./urls";
|
||||
import { countryCodeMap } from "@/assets/countryCodes";
|
||||
|
||||
// Fetch function for epoch rewards
|
||||
export const fetchEpochRewards = async (): Promise<
|
||||
@@ -46,7 +46,7 @@ export const fetchEpochRewards = async (): Promise<
|
||||
|
||||
// Fetch gateway status based on identity key
|
||||
export const fetchGatewayStatus = async (
|
||||
identityKey: string
|
||||
identityKey: string,
|
||||
): Promise<GatewayStatus | null> => {
|
||||
const response = await fetch(`${OBSERVATORY_GATEWAYS_URL}/${identityKey}`);
|
||||
|
||||
@@ -58,7 +58,7 @@ export const fetchGatewayStatus = async (
|
||||
};
|
||||
|
||||
export const fetchNodeDelegations = async (
|
||||
id: number
|
||||
id: number,
|
||||
): Promise<NodeRewardDetails[]> => {
|
||||
const response = await fetch(
|
||||
`${DATA_OBSERVATORY_NODES_URL}/${id}/delegations`,
|
||||
@@ -67,7 +67,7 @@ export const fetchNodeDelegations = async (
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -93,7 +93,7 @@ export const fetchCurrentEpoch = async () => {
|
||||
const data: CurrentEpochData = await response.json();
|
||||
const epochEndTime = addSeconds(
|
||||
new Date(data.current_epoch_start),
|
||||
data.epoch_length.secs
|
||||
data.epoch_length.secs,
|
||||
).toISOString();
|
||||
|
||||
return { ...data, current_epoch_end: epochEndTime };
|
||||
@@ -122,7 +122,9 @@ export const fetchBalances = async (address: string): Promise<number> => {
|
||||
};
|
||||
|
||||
// Fetch function to get total staker rewards
|
||||
export const fetchTotalStakerRewards = async (address: string): Promise<number> => {
|
||||
export const fetchTotalStakerRewards = async (
|
||||
address: string,
|
||||
): Promise<number> => {
|
||||
const response = await fetch(`${DATA_OBSERVATORY_BALANCES_URL}/${address}`, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
@@ -162,7 +164,7 @@ export const fetchOriginalStake = async (address: string): Promise<number> => {
|
||||
export const fetchNoise = async (): Promise<IPacketsAndStakingData[]> => {
|
||||
if (!process.env.NEXT_PUBLIC_NS_API_MIXNODES_STATS) {
|
||||
throw new Error(
|
||||
"NEXT_PUBLIC_NS_API_MIXNODES_STATS environment variable is not defined"
|
||||
"NEXT_PUBLIC_NS_API_MIXNODES_STATS environment variable is not defined",
|
||||
);
|
||||
}
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_NS_API_MIXNODES_STATS, {
|
||||
@@ -178,7 +180,7 @@ export const fetchNoise = async (): Promise<IPacketsAndStakingData[]> => {
|
||||
|
||||
// Fetch Account Balance
|
||||
export const fetchAccountBalance = async (
|
||||
address: string
|
||||
address: string,
|
||||
): Promise<IAccountBalancesInfo> => {
|
||||
const res = await fetch(`${NYM_ACCOUNT_ADDRESS}/${address}`, {
|
||||
headers: {
|
||||
@@ -208,7 +210,7 @@ export const fetchObservatoryNodes = async (): Promise<IObservatoryNode[]> => {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -261,12 +263,12 @@ export const fetchNSApiNodes = async (): Promise<NS_NODE[]> => {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch NS API nodes (page ${page}): ${response.statusText}`
|
||||
`Failed to fetch NS API nodes (page ${page}): ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -297,7 +299,7 @@ export const fetchWorldMapCountries =
|
||||
const countryCounts: Record<string, number> = {};
|
||||
|
||||
// Process each node
|
||||
nodes.forEach((node: NS_NODE) => {
|
||||
for (const node of nodes) {
|
||||
// Get the 2-letter country code from the node's geoip data
|
||||
const twoLetterCode = node.geoip?.country;
|
||||
|
||||
@@ -309,17 +311,17 @@ export const fetchWorldMapCountries =
|
||||
countryCounts[threeLetterCode] =
|
||||
(countryCounts[threeLetterCode] || 0) + 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Convert the counts to the required format
|
||||
const result: CountryDataResponse = {};
|
||||
|
||||
Object.entries(countryCounts).forEach(([threeLetterCode, count]) => {
|
||||
for (const [threeLetterCode, count] of Object.entries(countryCounts)) {
|
||||
result[threeLetterCode] = {
|
||||
ISO3: threeLetterCode,
|
||||
nodes: count,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { WorldMap } from "@/components/worldMap/WorldMap";
|
||||
import { Stack } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid2";
|
||||
import BlogArticlesCards from "../components/blogs/BlogArticleCards";
|
||||
@@ -10,7 +11,6 @@ import { StakersNumberCard } from "../components/landingPageComponents/StakersNu
|
||||
import { TokenomicsCard } from "../components/landingPageComponents/TokenomicsCard";
|
||||
import NodeTable from "../components/nodeTable/NodeTableWithAction";
|
||||
import NodeAndAddressSearch from "../components/search/NodeAndAddressSearch";
|
||||
import { WorldMap } from "@/components/worldMap/WorldMap";
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
||||
|
||||
+12033
-39713
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { fetchNSApiNodes, fetchObservatoryNodes } from "@/app/api";
|
||||
import { fetchObservatoryNodes } from "@/app/api";
|
||||
import type { IObservatoryNode } from "@/app/api/types";
|
||||
import { Skeleton, Typography, useTheme } from "@mui/material";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -19,21 +19,6 @@ export const StakersNumberCard = () => {
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
const {
|
||||
data: nsNodes,
|
||||
isLoading: loadingNsNodes,
|
||||
isError: errorNsNodes,
|
||||
} = useQuery({
|
||||
queryKey: ["nsNodes"],
|
||||
queryFn: () => fetchNSApiNodes(),
|
||||
staleTime: 10 * 60 * 1000, // 10 minutes
|
||||
refetchOnWindowFocus: false, // Prevents unnecessary refetching
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
console.log("nsNodes", nsNodes);
|
||||
|
||||
const theme = useTheme();
|
||||
const isDarkMode = theme.palette.mode === "dark";
|
||||
|
||||
@@ -61,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);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
import type { IObservatoryNode } from "@/app/api/types";
|
||||
import { NYM_ACCOUNT_ADDRESS } from "@/app/api/urls";
|
||||
import { Search } from "@mui/icons-material";
|
||||
import {
|
||||
Autocomplete,
|
||||
@@ -13,7 +14,6 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { fetchObservatoryNodes } from "../../app/api";
|
||||
import { NYM_ACCOUNT_ADDRESS } from "@/app/api/urls";
|
||||
|
||||
const NodeAndAddressSearch = () => {
|
||||
const router = useRouter();
|
||||
@@ -50,7 +50,7 @@ const NodeAndAddressSearch = () => {
|
||||
}
|
||||
} catch {
|
||||
setErrorText(
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again."
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again.",
|
||||
);
|
||||
setIsLoading(false); // Stop loading
|
||||
|
||||
@@ -58,7 +58,7 @@ const NodeAndAddressSearch = () => {
|
||||
}
|
||||
} else {
|
||||
setErrorText(
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again."
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again.",
|
||||
);
|
||||
setIsLoading(false); // Stop loading
|
||||
|
||||
@@ -68,7 +68,7 @@ const NodeAndAddressSearch = () => {
|
||||
// Check if it's a node identity key
|
||||
if (nymNodes) {
|
||||
const matchingNode = nymNodes.find(
|
||||
(node) => node.identity_key === inputValue
|
||||
(node) => node.identity_key === inputValue,
|
||||
);
|
||||
|
||||
if (matchingNode) {
|
||||
@@ -77,13 +77,13 @@ const NodeAndAddressSearch = () => {
|
||||
}
|
||||
}
|
||||
setErrorText(
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again."
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again.",
|
||||
);
|
||||
setIsLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setErrorText(
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again."
|
||||
"No node found with the provided Name, Node ID or Identity Key. Please check your input and try again.",
|
||||
);
|
||||
console.error(error);
|
||||
setIsLoading(false); // Stop loading
|
||||
@@ -92,7 +92,7 @@ const NodeAndAddressSearch = () => {
|
||||
|
||||
// Handle search input change
|
||||
const handleSearchInputChange = (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
event: React.ChangeEvent<HTMLInputElement>,
|
||||
) => {
|
||||
const value = event.target.value;
|
||||
setInputValue(value);
|
||||
@@ -107,7 +107,7 @@ const NodeAndAddressSearch = () => {
|
||||
const filteredNodes = nymNodes.filter((node) =>
|
||||
node.self_description?.moniker
|
||||
?.toLowerCase()
|
||||
.includes(value.toLowerCase())
|
||||
.includes(value.toLowerCase()),
|
||||
);
|
||||
setSearchOptions(filteredNodes);
|
||||
} else {
|
||||
@@ -118,7 +118,7 @@ const NodeAndAddressSearch = () => {
|
||||
// Handle node selection from dropdown
|
||||
const handleNodeSelect = (
|
||||
event: React.SyntheticEvent,
|
||||
value: string | IObservatoryNode | null
|
||||
value: string | IObservatoryNode | null,
|
||||
) => {
|
||||
if (value && typeof value !== "string") {
|
||||
setIsLoading(true); // Show loading spinner
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { scaleLinear } from "d3-scale";
|
||||
import * as React from "react";
|
||||
import {
|
||||
ComposableMap,
|
||||
Geographies,
|
||||
@@ -10,18 +10,17 @@ import {
|
||||
} from "react-simple-maps";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import "react-tooltip/dist/react-tooltip.css";
|
||||
import { Skeleton, Stack, Typography, IconButton } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { CountryDataResponse } from "../../app/api/types";
|
||||
import MAP_TOPOJSON from "../../assets/world-110m.json";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { fetchWorldMapCountries } from "@/app/api";
|
||||
import ExplorerCard from "../cards/ExplorerCard";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import RemoveIcon from "@mui/icons-material/Remove";
|
||||
import RestartAltIcon from "@mui/icons-material/RestartAlt";
|
||||
import { IconButton, Skeleton, Stack, Typography } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { CountryDataResponse } from "../../app/api/types";
|
||||
import MAP_TOPOJSON from "../../assets/world-110m.json";
|
||||
|
||||
export const WorldMap = ({}): JSX.Element => {
|
||||
export const WorldMap = (): JSX.Element => {
|
||||
const theme = useTheme();
|
||||
const isDarkMode = theme.palette.mode === "dark";
|
||||
const [position, setPosition] = React.useState<{
|
||||
@@ -42,14 +41,19 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
refetchOnMount: false,
|
||||
});
|
||||
|
||||
const [tooltipContent, setTooltipContent] = React.useState<string | null>(
|
||||
null
|
||||
);
|
||||
const [tooltipContent, setTooltipContent] = React.useState<string>("");
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleMouseLeave = () => setTooltipContent("");
|
||||
return () => {
|
||||
handleMouseLeave();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const colorScale = React.useMemo(() => {
|
||||
if (countries) {
|
||||
const heighestNumberOfNodes = Math.max(
|
||||
...Object.values(countries).map((country) => country.nodes)
|
||||
...Object.values(countries).map((country) => country.nodes),
|
||||
);
|
||||
return scaleLinear<string, string>()
|
||||
.domain([
|
||||
@@ -74,34 +78,25 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
"#147A3D", // Medium green
|
||||
"#1A994C", // Light green
|
||||
theme.palette.accent.main,
|
||||
]
|
||||
],
|
||||
)
|
||||
.unknown(isDarkMode ? theme.palette.pine[950] : theme.palette.pine[25]);
|
||||
}
|
||||
return () =>
|
||||
isDarkMode ? theme.palette.pine[950] : theme.palette.pine[25];
|
||||
}, [
|
||||
countries,
|
||||
theme.palette.mode,
|
||||
theme.palette.pine,
|
||||
theme.palette.accent,
|
||||
isDarkMode,
|
||||
]);
|
||||
}, [countries, theme.palette.pine, theme.palette.accent, isDarkMode]);
|
||||
|
||||
if (isLoadingCountries) {
|
||||
return (
|
||||
<ExplorerCard label="Nym Nodes in the world">
|
||||
<Stack gap={1}>
|
||||
<Skeleton variant="text" />
|
||||
<Skeleton variant="text" height={238} />
|
||||
</Stack>
|
||||
</ExplorerCard>
|
||||
<Stack gap={1} width="100%">
|
||||
<Skeleton variant="text" height={238} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (isCountriesError) {
|
||||
return (
|
||||
<ExplorerCard label="Nym Nodes in the world">
|
||||
<Stack gap={1}>
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
@@ -112,12 +107,11 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
Failed to load data
|
||||
</Typography>
|
||||
<Skeleton variant="text" height={238} />
|
||||
</ExplorerCard>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
// <ExplorerCard label="Nym Nodes in the world">
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
@@ -127,9 +121,7 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
margin: "0 auto",
|
||||
}}
|
||||
>
|
||||
{/* <div style={{ width: "90%", margin: "0 auto" }}> */}
|
||||
<ComposableMap
|
||||
{...({} as any)}
|
||||
data-tip=""
|
||||
style={{
|
||||
backgroundColor: isDarkMode ? "#000000" : theme.palette.pine[25],
|
||||
@@ -160,6 +152,10 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
}) => {
|
||||
setPosition({ coordinates, zoom });
|
||||
}}
|
||||
onClick={(e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<Geographies geography={MAP_TOPOJSON}>
|
||||
{({ geographies }: { geographies: GeoJSON.Feature[] }) =>
|
||||
@@ -171,7 +167,9 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
] || { nodes: 0 };
|
||||
return (
|
||||
<Geography
|
||||
key={`${geo.properties?.ISO_A3 || ""}-${geo.id}-${geo.properties?.NAME_LONG || ""}`}
|
||||
key={`${geo.properties?.ISO_A3 || ""}-${geo.id}-${
|
||||
geo.properties?.NAME_LONG || ""
|
||||
}`}
|
||||
geography={geo}
|
||||
fill={colorScale(d?.nodes || 0)}
|
||||
stroke={
|
||||
@@ -185,7 +183,6 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
const { NAME_LONG } = geo.properties as {
|
||||
NAME_LONG: string;
|
||||
};
|
||||
|
||||
setTooltipContent(`${NAME_LONG} | ${d?.nodes || 0}`);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
@@ -196,8 +193,15 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
? {
|
||||
fill: theme.palette.accent.main,
|
||||
outline: "white",
|
||||
cursor: "pointer",
|
||||
}
|
||||
: undefined,
|
||||
default: {
|
||||
outline: "none",
|
||||
},
|
||||
pressed: {
|
||||
outline: "none",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -206,7 +210,6 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
</Geographies>
|
||||
</ZoomableGroup>
|
||||
</ComposableMap>
|
||||
{/* </div> */}
|
||||
|
||||
<div
|
||||
style={{
|
||||
@@ -286,7 +289,8 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
</div>
|
||||
<Tooltip
|
||||
id="map-tooltip"
|
||||
content={tooltipContent || ""}
|
||||
content={tooltipContent}
|
||||
float={true}
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
padding: "4px 8px",
|
||||
@@ -299,10 +303,9 @@ export const WorldMap = ({}): JSX.Element => {
|
||||
? theme.palette.base.white
|
||||
: theme.palette.pine[950],
|
||||
borderRadius: "4px",
|
||||
zIndex: 1000,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
/>
|
||||
{/* // </ExplorerCard> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
declare module "react-simple-maps" {
|
||||
import { FunctionComponent, ReactNode } from "react";
|
||||
import { Feature, Geometry, GeoJsonProperties } from "geojson";
|
||||
import type { FunctionComponent, ReactNode } from "react";
|
||||
import type { Feature, Geometry, GeoJsonProperties } from "geojson";
|
||||
|
||||
export interface ComposableMapProps {
|
||||
children?: ReactNode;
|
||||
@@ -13,6 +13,7 @@ declare module "react-simple-maps" {
|
||||
}
|
||||
|
||||
export interface GeographiesProps {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
geography: any;
|
||||
children?: (props: {
|
||||
geographies: Feature<Geometry, GeoJsonProperties>[];
|
||||
@@ -21,6 +22,7 @@ declare module "react-simple-maps" {
|
||||
|
||||
export interface GeographyProps {
|
||||
geography: Feature<Geometry, GeoJsonProperties>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
Reference in New Issue
Block a user