Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/network store #369

Merged
merged 1 commit into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/deploy-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@akashnetwork/akashjs": "^0.10.0",
"@akashnetwork/env-loader": "*",
"@akashnetwork/http-sdk": "*",
"@akashnetwork/network-store": "*",
"@akashnetwork/ui": "*",
"@auth0/nextjs-auth0": "^3.5.0",
"@chain-registry/types": "^0.41.3",
Expand Down
2 changes: 1 addition & 1 deletion apps/deploy-web/src/components/layout/NodeStatusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import { Button } from "@akashnetwork/ui/components";
import { useRouter } from "next/navigation";

import { useSettings } from "@src/context/SettingsProvider";
import { getSplitText } from "@src/hooks/useShortText";
import networkStore from "@src/store/networkStore";
import { UrlService } from "@src/utils/urlUtils";
import { useSettings } from "../../context/SettingsProvider";
import { LinearLoadingSkeleton } from "../shared/LinearLoadingSkeleton";
import { NodeStatus } from "../shared/NodeStatus";

Expand Down
4 changes: 2 additions & 2 deletions apps/deploy-web/src/components/new-deployment/BidGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import { useEffect, useState } from "react";
import { MAINNET_ID } from "@akashnetwork/network-store";
import { Alert, Table, TableBody, TableCell, TableHeader, TableRow } from "@akashnetwork/ui/components";
import { Check } from "iconoir-react";

import { MAINNET_ID } from "@src/config/network.config";
import networkStore from "@src/store/networkStore";
import { BidDto, DeploymentDto } from "@src/types/deployment";
import { ApiProviderList } from "@src/types/provider";
Expand Down Expand Up @@ -46,7 +46,7 @@ export const BidGroup: React.FunctionComponent<Props> = ({
}) => {
const [resources, setResources] = useState<{ cpuAmount: number; gpuAmount: number; memoryAmount: number; storageAmount: number } | null>(null);
const fBids = bids.filter(bid => filteredBids.includes(bid.id));
const { id: selectedNetworkId } = networkStore.useSelectedNetwork();
const selectedNetworkId = networkStore.useSelectedNetworkId();

useEffect(() => {
const currentGroup = deploymentDetail?.groups.find(g => g.group_id.gseq === gseq);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"use client";
import { useState } from "react";
import { MAINNET_ID } from "@akashnetwork/network-store";
import { Alert, AlertDescription, AlertTitle, Badge, buttonVariants, Popup, RadioGroup, RadioGroupItem } from "@akashnetwork/ui/components";
import { useAtom } from "jotai/index";

import { MAINNET_ID } from "@src/config/network.config";
import networkStore, { networks } from "@src/store/networkStore";
import networkStore from "@src/store/networkStore";
import { cn } from "@src/utils/styleUtils";

export const SelectNetworkModal = ({ onClose }) => {
const [selectedNetworkId, setSelectedNetworkId] = useAtom(networkStore.selectedNetworkId);
const [selectedNetworkId, setSelectedNetworkId] = networkStore.useSelectedNetworkIdStore({ reloadOnChange: true });
const [formSelectedNetworkId, setFormSelectedNetworkId] = useState(selectedNetworkId);

const save = () => {
Expand Down Expand Up @@ -45,7 +44,7 @@ export const SelectNetworkModal = ({ onClose }) => {
>
<RadioGroup>
<ul>
{networks.map(network => {
{networkStore.networks.map(network => {
return (
<li
key={network.id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const SettingsContainer: React.FunctionComponent = () => {
<LabelValue
value={
<div className="inline-flex items-center">
<strong>{selectedNetwork?.title}</strong>
<strong>{selectedNetwork.title}</strong>

<Button onClick={() => setIsSelectingNetwork(true)} size="icon" className="ml-4" variant="outline">
<Edit className="text-sm" />
Expand Down
3 changes: 1 addition & 2 deletions apps/deploy-web/src/config/denom.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { MainnetNetworkId, SandboxNetworkId } from "@akashnetwork/akashjs/build/types/network";

import { MAINNET_ID, SANDBOX_ID } from "@src/config/network.config";
import { MAINNET_ID, SANDBOX_ID } from "@akashnetwork/network-store";

export const UAKT_DENOM = "uakt";
export const USDC_IBC_DENOMS: Record<MainnetNetworkId | SandboxNetworkId, string> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import axios from "axios";
import { useLocalStorage } from "@src/hooks/useLocalStorage";
import { usePreviousRoute } from "@src/hooks/usePreviousRoute";
import { queryClient } from "@src/queries";
import networkStore, { initiateNetworkVersions } from "@src/store/networkStore";
import networkStore from "@src/store/networkStore";
import type { FCWithChildren } from "@src/types/component";
import { NodeStatus } from "@src/types/node";
import type { NodeStatus } from "@src/types/node";
import { initAppTypes } from "@src/utils/init";
import { migrateLocalStorage } from "@src/utils/localStorage";

Expand Down Expand Up @@ -57,16 +57,19 @@ export const SettingsProvider: FCWithChildren = ({ children }) => {
const { getLocalStorageItem, setLocalStorageItem } = useLocalStorage();
const { isCustomNode, customNode, nodes, apiEndpoint, rpcEndpoint } = settings;
const selectedNetwork = networkStore.useSelectedNetwork();
const [{ isLoading: isLoadingNetworks }] = networkStore.useNetworksStore();

usePreviousRoute();

// load settings from localStorage or set default values
useEffect(() => {
if (isLoadingNetworks) {
return;
}

const initiateSettings = async () => {
setIsLoadingSettings(true);

await initiateNetworkVersions();

// Apply local storage migrations
migrateLocalStorage();

Expand Down Expand Up @@ -139,7 +142,7 @@ export const SettingsProvider: FCWithChildren = ({ children }) => {

initiateSettings();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [isLoadingNetworks]);

/**
* Load the node status from status rpc endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ export function useWallet() {
}

const TransactionSnackbarContent = ({ snackMessage, transactionHash }) => {
const selectedNetwork = networkStore.useSelectedNetwork();
const txUrl = transactionHash && `${browserEnvConfig.NEXT_PUBLIC_STATS_APP_URL}/transactions/${transactionHash}?network=${selectedNetwork.id}`;
const selectedNetworkId = networkStore.useSelectedNetworkId();
const txUrl = transactionHash && `${browserEnvConfig.NEXT_PUBLIC_STATS_APP_URL}/transactions/${transactionHash}?network=${selectedNetworkId}`;

return (
<>
Expand Down
6 changes: 2 additions & 4 deletions apps/deploy-web/src/hooks/useDenom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { USDC_IBC_DENOMS } from "@src/config/denom.config";
import networkStore from "@src/store/networkStore";

export const useUsdcDenom = () => {
const selectedNetwork = networkStore.useSelectedNetwork();
return USDC_IBC_DENOMS[selectedNetwork.id];
return USDC_IBC_DENOMS[networkStore.selectedNetworkId];
};

export const getUsdcDenom = () => {
const selectedNetwork = networkStore.getSelectedNetwork();
return USDC_IBC_DENOMS[selectedNetwork.id];
return USDC_IBC_DENOMS[networkStore.selectedNetworkId];
};

export const useSdlDenoms = () => {
Expand Down
86 changes: 4 additions & 82 deletions apps/deploy-web/src/hooks/useLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import { useEffect, useState } from "react";
import { useEventListener } from "usehooks-ts";

import { useWallet } from "@src/context/WalletProvider";
import networkStore from "@src/store/networkStore";

export const useLocalStorage = () => {
const { address } = useWallet();
const selectedNetwork = networkStore.useSelectedNetwork();
const selectedNetworkId = networkStore.useSelectedNetworkId();

const getLocalStorageItem = (key: string) => {
return localStorage.getItem(`${selectedNetwork.id}${address ? "/" + address : ""}/${key}`);
return localStorage.getItem(`${selectedNetworkId}${address ? "/" + address : ""}/${key}`);
};

const setLocalStorageItem = (key: string, value: string) => {
localStorage.setItem(`${selectedNetwork.id}${address ? "/" + address : ""}/${key}`, value);
localStorage.setItem(`${selectedNetworkId}${address ? "/" + address : ""}/${key}`, value);
};

const removeLocalStorageItem = (key: string) => {
localStorage.removeItem(`${selectedNetwork.id}${address ? "/" + address : ""}/${key}`);
localStorage.removeItem(`${selectedNetworkId}${address ? "/" + address : ""}/${key}`);
};

return {
Expand All @@ -26,78 +23,3 @@ export const useLocalStorage = () => {
getLocalStorageItem
};
};

export function useCustomLocalStorage<T>(key: string, initialValue: T) {
// Get from local storage then
// parse stored json or return initialValue
const readValue = () => {
// Prevent build error "window is undefined" but keep keep working
if (typeof window === "undefined") {
return initialValue;
}

try {
const item = window.localStorage.getItem(key);
return item ? (parseJSON(item) as T) : initialValue;
} catch (error) {
console.warn(`Error reading localStorage key “${key}”:`, error);
return initialValue;
}
};

// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState<T>(readValue);

// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value: T | ((newValue: T) => T)) => {
// Prevent build error "window is undefined" but keeps working
if (typeof window == "undefined") {
console.warn(`Tried setting localStorage key “${key}” even though environment is not a client`);
}

try {
// Allow value to be a function so we have the same API as useState
const newValue = value instanceof Function ? value(storedValue) : value;

// Save to local storage
window.localStorage.setItem(key, JSON.stringify(newValue));

// Save state
setStoredValue(newValue);

// We dispatch a custom event so every useLocalStorage hook are notified
window.dispatchEvent(new Event("local-storage"));
} catch (error) {
console.warn(`Error setting localStorage key “${key}”:`, error);
}
};

useEffect(() => {
setStoredValue(readValue());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const handleStorageChange = () => {
setStoredValue(readValue());
};

// this only works for other documents, not the current one
useEventListener("storage", handleStorageChange);

// this is a custom event, triggered in writeValueToLocalStorage
// See: useLocalStorage()
useEventListener("local-storage", handleStorageChange);

return [storedValue, setValue];
}

// A wrapper for "JSON.parse()"" to support "undefined" value
function parseJSON(value: string) {
try {
return value === "undefined" ? undefined : JSON.parse(value ?? "");
} catch (error) {
return value === "undefined" ? undefined : value;
}
}
3 changes: 1 addition & 2 deletions apps/deploy-web/src/hooks/useManagedWallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useEffect, useMemo } from "react";
import { useAtom } from "jotai/index";

import { browserEnvConfig } from "@src/config/browser-env.config";
import { useUser } from "@src/hooks/useUser";
Expand All @@ -17,7 +16,7 @@ export const useManagedWallet = () => {
const { mutate: create, data: created, isLoading: isCreating, isSuccess: isCreated } = useCreateManagedWalletMutation();
const wallet = useMemo(() => queried || created, [queried, created]);
const isLoading = isFetching || isCreating;
const [selectedNetworkId, setSelectedNetworkId] = useAtom(networkStore.selectedNetworkId);
const [selectedNetworkId, setSelectedNetworkId] = networkStore.useSelectedNetworkIdStore({ reloadOnChange: true });

useEffect(() => {
if (!isBillingEnabled) {
Expand Down
2 changes: 1 addition & 1 deletion apps/deploy-web/src/services/api-url/api-url.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { NetworkId } from "@akashnetwork/akashjs/build/types/network";
import { SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store";

import type { BrowserEnvConfig, ServerEnvConfig } from "@src/config/env-config.schema";
import { SANDBOX_ID, TESTNET_ID } from "@src/config/network.config";

export class ApiUrlService {
constructor(
Expand Down
81 changes: 6 additions & 75 deletions apps/deploy-web/src/store/networkStore.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,10 @@
import axios from "axios";
import { atom } from "jotai";
import { useAtom } from "jotai/index";
import { atomWithStorage } from "jotai/utils";
import cloneDeep from "lodash/cloneDeep";
import { NetworkStore } from "@akashnetwork/network-store";

import { browserEnvConfig } from "@src/config/browser-env.config";
import { INITIAL_NETWORKS_CONFIG } from "@src/config/network.config";
import { store } from "@src/store/global-store";
import type { Network } from "@src/types/network";

export const networks: Network[] = cloneDeep(INITIAL_NETWORKS_CONFIG);

export const initiateNetworkVersions = async () => {
await Promise.all(
networks.map(async network => {
try {
const response = await axios.get<string>(network.versionUrl, { timeout: 10000 });
network.version = response.data;
return;
} catch (error) {
console.error(error);
}
})
);
};

const selectedNetworkId = atomWithStorage<Network["id"]>(
"selectedNetworkId",
browserEnvConfig.NEXT_PUBLIC_DEFAULT_NETWORK_ID,
// TODO: remove this once we have all clients using this store instead of the localstorage
// Issue: https://github.com/akash-network/console/issues/297
typeof window !== "undefined"
? {
setItem: (key, value) => {
localStorage.setItem(key, value);
location.reload();
},
getItem: key => {
const stored = localStorage.getItem(key) as Network["id"] | null;

if (!stored) {
localStorage.setItem(key, browserEnvConfig.NEXT_PUBLIC_DEFAULT_NETWORK_ID);
return browserEnvConfig.NEXT_PUBLIC_DEFAULT_NETWORK_ID;
}

return stored;
},
removeItem: key => {
localStorage.removeItem(key);
location.reload();
}
}
: undefined,
{ getOnInit: true }
);
const selectedNetwork = atom<Network, [Network], void>(
get => {
const networkId = get(selectedNetworkId);
return networks.find(n => n.id === networkId) ?? networks[0];
},
(get, set, next) => {
set(selectedNetworkId, next.id);
}
);

export default {
selectedNetworkId,
selectedNetwork,
getSelectedNetwork: () => store.get(selectedNetwork),
getSelectedNetworkId: () => store.get(selectedNetwork).id,
useSelectedNetwork: () => useAtom(selectedNetwork)[0],
get apiVersion() {
return store.get(selectedNetwork).apiVersion;
},
get marketApiVersion() {
return store.get(selectedNetwork).marketApiVersion;
}
};
export default NetworkStore.create({
defaultNetworkId: browserEnvConfig.NEXT_PUBLIC_DEFAULT_NETWORK_ID,
apiBaseUrl: browserEnvConfig.NEXT_PUBLIC_API_BASE_URL,
store
});
2 changes: 1 addition & 1 deletion apps/deploy-web/src/utils/apiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class ApiUrlService {
}

static get baseApiUrl() {
return browserApiUrlService.getBaseApiUrlFor(networkStore.getSelectedNetworkId());
return browserApiUrlService.getBaseApiUrlFor(networkStore.selectedNetworkId);
}
}

Expand Down
6 changes: 2 additions & 4 deletions apps/deploy-web/src/utils/deploymentData/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NetworkId } from "@akashnetwork/akashjs/build/types/network";
import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@akashnetwork/network-store";

import { MAINNET_ID, SANDBOX_ID, TESTNET_ID } from "@src/config/network.config";
import networkStore from "@src/store/networkStore";
import * as v1beta3 from "./v1beta3";
export * from "./helpers";
Expand All @@ -11,6 +11,4 @@ const NETWORK_SDL: Record<NetworkId, typeof v1beta3> = {
[SANDBOX_ID]: v1beta3
};

export const selectedNetwork = networkStore.getSelectedNetwork();
export const selectedNetworkId = selectedNetwork.id;
export const deploymentData = NETWORK_SDL[selectedNetworkId];
export const deploymentData = NETWORK_SDL[networkStore.selectedNetworkId];
Loading
Loading