refactor EnvironmentProvider, add environment to NodesTable
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
NYM_ACCOUNT_ADDRESS,
|
||||
NYM_PRICES_API,
|
||||
OBSERVATORY_GATEWAYS_URL,
|
||||
SANDBOX_NS_API_NODES,
|
||||
} from "./urls";
|
||||
|
||||
// Fetch function for epoch rewards
|
||||
@@ -118,7 +119,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",
|
||||
@@ -205,8 +208,13 @@ export const fetchNymPrice = async (): Promise<NymTokenomics> => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export const fetchNSApiNodes = async (): Promise<NS_NODE[]> => {
|
||||
if (!NS_API_NODES) {
|
||||
export const fetchNSApiNodes = async (
|
||||
environment: Environment
|
||||
): Promise<NS_NODE[]> => {
|
||||
const baseUrl =
|
||||
environment === "sandbox" ? SANDBOX_NS_API_NODES : NS_API_NODES;
|
||||
|
||||
if (!baseUrl) {
|
||||
throw new Error("NS_API_NODES URL is not defined");
|
||||
}
|
||||
|
||||
@@ -217,15 +225,12 @@ export const fetchNSApiNodes = async (): Promise<NS_NODE[]> => {
|
||||
let hasMoreData = true;
|
||||
|
||||
while (hasMoreData) {
|
||||
const response = await fetch(
|
||||
`${NS_API_NODES}?page=${page}&size=${PAGE_SIZE}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await fetch(`${baseUrl}?page=${page}&size=${PAGE_SIZE}`, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
|
||||
@@ -8,7 +8,6 @@ export const Environment: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
const { environment, setEnvironment } = useEnvironment();
|
||||
|
||||
console.log("environment", environment);
|
||||
|
||||
const explorerName = environment
|
||||
? `${environment} Explorer`
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -14,7 +14,9 @@ import FilterAltIcon from "@mui/icons-material/FilterAlt";
|
||||
import AccessTimeIcon from "@mui/icons-material/AccessTime";
|
||||
import PieChartIcon from "@mui/icons-material/PieChart";
|
||||
import PercentIcon from "@mui/icons-material/Percent";
|
||||
import NodeFilterButtonGroup from "../toggleButton/NodeFilterButtonGroup";
|
||||
import NodeFilterButtonGroup, {
|
||||
type Option,
|
||||
} from "../toggleButton/NodeFilterButtonGroup";
|
||||
import { RECOMMENDED_NODES } from "@/app/constants";
|
||||
|
||||
type AdvancedFiltersProps = {
|
||||
@@ -36,6 +38,7 @@ type AdvancedFiltersProps = {
|
||||
mixnodes: number;
|
||||
gateways: number;
|
||||
};
|
||||
environment: "mainnet" | "sandbox";
|
||||
};
|
||||
|
||||
export default function AdvancedFilters({
|
||||
@@ -51,6 +54,7 @@ export default function AdvancedFilters({
|
||||
activeFilter,
|
||||
setActiveFilter,
|
||||
nodeCounts,
|
||||
environment,
|
||||
}: AdvancedFiltersProps) {
|
||||
const theme = useTheme();
|
||||
const green = "#14e76f"; // from theme colours
|
||||
@@ -248,6 +252,54 @@ export default function AdvancedFilters({
|
||||
</Box>
|
||||
);
|
||||
|
||||
const filterOptions =
|
||||
environment === "mainnet"
|
||||
? [
|
||||
{
|
||||
label: `Recommended servers (${RECOMMENDED_NODES.length})`,
|
||||
isSelected: activeFilter === "recommended",
|
||||
value: "recommended" as const,
|
||||
},
|
||||
{
|
||||
label: `All servers (${nodeCounts.all})`,
|
||||
isSelected: activeFilter === "all",
|
||||
value: "all" as const,
|
||||
},
|
||||
{
|
||||
label: `Mixnodes (${nodeCounts.mixnodes})`,
|
||||
isSelected: activeFilter === "mixnodes",
|
||||
value: "mixnodes" as const,
|
||||
},
|
||||
{
|
||||
label: `Gateways (${nodeCounts.gateways})`,
|
||||
isSelected: activeFilter === "gateways",
|
||||
value: "gateways" as const,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: `All servers (${nodeCounts.all})`,
|
||||
isSelected: activeFilter === "all",
|
||||
value: "all" as const,
|
||||
},
|
||||
{
|
||||
label: `Mixnodes (${nodeCounts.mixnodes})`,
|
||||
isSelected: activeFilter === "mixnodes",
|
||||
value: "mixnodes" as const,
|
||||
},
|
||||
{
|
||||
label: `Gateways (${nodeCounts.gateways})`,
|
||||
isSelected: activeFilter === "gateways",
|
||||
value: "gateways" as const,
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (environment === "sandbox" && activeFilter === "recommended") {
|
||||
setActiveFilter("all");
|
||||
}
|
||||
}, [environment, activeFilter, setActiveFilter]);
|
||||
|
||||
return (
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Box
|
||||
@@ -261,28 +313,7 @@ export default function AdvancedFilters({
|
||||
<Box sx={{ width: { xs: "100%", sm: "auto" } }}>
|
||||
<NodeFilterButtonGroup
|
||||
size="medium"
|
||||
options={[
|
||||
{
|
||||
label: `Recommended servers (${RECOMMENDED_NODES.length})`,
|
||||
isSelected: activeFilter === "recommended",
|
||||
value: "recommended",
|
||||
},
|
||||
{
|
||||
label: `All servers (${nodeCounts.all})`,
|
||||
isSelected: activeFilter === "all",
|
||||
value: "all",
|
||||
},
|
||||
{
|
||||
label: `Mixnodes (${nodeCounts.mixnodes})`,
|
||||
isSelected: activeFilter === "mixnodes",
|
||||
value: "mixnodes",
|
||||
},
|
||||
{
|
||||
label: `Gateways (${nodeCounts.gateways})`,
|
||||
isSelected: activeFilter === "gateways",
|
||||
value: "gateways",
|
||||
},
|
||||
]}
|
||||
options={filterOptions}
|
||||
onPage={activeFilter}
|
||||
onFilterChange={setActiveFilter}
|
||||
/>
|
||||
|
||||
@@ -10,6 +10,7 @@ import NodeTable from "./NodeTable";
|
||||
import { useState, useEffect } from "react";
|
||||
import AdvancedFilters from "./AdvancedFilters";
|
||||
import { RECOMMENDED_NODES } from "@/app/constants";
|
||||
import { useEnvironment } from "@/providers/EnvironmentProvider";
|
||||
|
||||
// Utility function to calculate node saturation point
|
||||
function getNodeSaturationPoint(
|
||||
@@ -114,6 +115,8 @@ const NodeTableWithAction = () => {
|
||||
return stored ? JSON.parse(stored) : false;
|
||||
});
|
||||
|
||||
const { environment } = useEnvironment();
|
||||
|
||||
// Wrapper functions to handle filter changes and sessionStorage
|
||||
const handleActiveFilterChange = (
|
||||
newFilter: "all" | "mixnodes" | "gateways" | "recommended"
|
||||
@@ -171,8 +174,8 @@ const NodeTableWithAction = () => {
|
||||
isLoading: isNSApiNodesLoading,
|
||||
isError: isNSApiNodesError,
|
||||
} = useQuery({
|
||||
queryKey: ["nsApiNodes"],
|
||||
queryFn: fetchNSApiNodes,
|
||||
queryKey: ["nsApiNodes", environment],
|
||||
queryFn: () => fetchNSApiNodes(environment),
|
||||
staleTime: 10 * 60 * 1000, // 10 minutes
|
||||
refetchOnWindowFocus: false, // Prevents unnecessary refetching
|
||||
refetchOnReconnect: false,
|
||||
@@ -290,6 +293,7 @@ const NodeTableWithAction = () => {
|
||||
activeFilter={activeFilter}
|
||||
setActiveFilter={handleActiveFilterChange}
|
||||
nodeCounts={nodeCounts}
|
||||
environment={environment}
|
||||
/>
|
||||
<NodeTable nodes={filteredNodes} />
|
||||
</Stack>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
import { Button, ButtonGroup, Stack } from "@mui/material";
|
||||
|
||||
type Option = {
|
||||
export type Option = {
|
||||
label: string;
|
||||
isSelected: boolean;
|
||||
value: "all" | "mixnodes" | "gateways" | "recommended";
|
||||
};
|
||||
|
||||
type Options = [Option, Option, Option, Option];
|
||||
type Options = Option[];
|
||||
|
||||
const NodeFilterButtonGroup = ({
|
||||
size = "small",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
type Environment = "mainnet" | "sandbox";
|
||||
|
||||
@@ -14,30 +15,40 @@ const EnvironmentContext = createContext<EnvironmentContextType | undefined>(
|
||||
|
||||
const ENVIRONMENT_STORAGE_KEY = "environment";
|
||||
|
||||
const ClientStorage = dynamic(
|
||||
() =>
|
||||
import("@uidotdev/usehooks").then((mod) => {
|
||||
const { useLocalStorage } = mod;
|
||||
return function ClientStorageComponent({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const [stored, setStored] = useLocalStorage<{ env: Environment }>(
|
||||
ENVIRONMENT_STORAGE_KEY,
|
||||
{ env: "mainnet" }
|
||||
);
|
||||
|
||||
const setEnvironment = (env: Environment) => {
|
||||
setStored({ env });
|
||||
};
|
||||
|
||||
return (
|
||||
<EnvironmentContext.Provider
|
||||
value={{ environment: stored.env, setEnvironment }}
|
||||
>
|
||||
{children}
|
||||
</EnvironmentContext.Provider>
|
||||
);
|
||||
};
|
||||
}),
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
export const EnvironmentProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [environment, setEnvironmentState] = useState<Environment>(() => {
|
||||
// Try to get the environment from localStorage on initial load
|
||||
const storedEnv = localStorage.getItem(ENVIRONMENT_STORAGE_KEY);
|
||||
return (storedEnv as Environment) || "mainnet";
|
||||
});
|
||||
|
||||
const setEnvironment = (env: Environment) => {
|
||||
setEnvironmentState(env);
|
||||
localStorage.setItem(ENVIRONMENT_STORAGE_KEY, env);
|
||||
};
|
||||
|
||||
// Update localStorage when environment changes
|
||||
useEffect(() => {
|
||||
localStorage.setItem(ENVIRONMENT_STORAGE_KEY, environment);
|
||||
}, [environment]);
|
||||
|
||||
return (
|
||||
<EnvironmentContext.Provider value={{ environment, setEnvironment }}>
|
||||
{children}
|
||||
</EnvironmentContext.Provider>
|
||||
);
|
||||
return <ClientStorage>{children}</ClientStorage>;
|
||||
};
|
||||
|
||||
export const useEnvironment = () => {
|
||||
|
||||
Reference in New Issue
Block a user