From a26efde7d52e08c397bfdf15600c5133ccad7920 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 3 Jul 2023 08:19:27 +0200 Subject: [PATCH] Add ChainsProvider with useChains --- context/ChainsContext/index.tsx | 91 +++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 context/ChainsContext/index.tsx diff --git a/context/ChainsContext/index.tsx b/context/ChainsContext/index.tsx new file mode 100644 index 0000000..3aab2ec --- /dev/null +++ b/context/ChainsContext/index.tsx @@ -0,0 +1,91 @@ +import { ReactNode, createContext, useContext, useEffect, useReducer } from "react"; +import { setChain, setChains, setChainsError } from "./helpers"; +import { getChain, getChainFromRegistry, getChainItemsFromRegistry } from "./service"; +import { storeChain } from "./storage"; +import { Action, ChainsContextType, State } from "./types"; + +const ChainsContext = createContext(undefined); + +const chainsReducer = (state: State, action: Action) => { + switch (action.type) { + case "setChains": { + return { ...state, chains: action.payload }; + } + case "setChain": { + storeChain(action.payload); + return { ...state, chain: action.payload }; + } + case "setChainsError": { + return { ...state, chainsError: action.payload }; + } + default: { + throw new Error("Unhandled action type"); + } + } +}; + +interface ChainsProviderProps { + readonly children: ReactNode; +} + +export const ChainsProvider = ({ children }: ChainsProviderProps) => { + const [state, dispatch] = useReducer(chainsReducer, { + chain: getChain(), + chains: { mainnets: [], testnets: [] }, + }); + + useEffect(() => { + (async function getChainsFromGithubRegistry() { + try { + const newChainItems = await getChainItemsFromRegistry(); + setChains(dispatch, newChainItems); + } catch (error) { + if (error instanceof Error) { + setChainsError(dispatch, error.message); + } else { + setChainsError(dispatch, "Failed to get chains from registry"); + } + } + })(); + }, []); + + useEffect(() => { + (async function getChainFromRegistryIfEmpty() { + if (!state.chain.chainId && state.chains.mainnets.length && state.chains.testnets.length) { + const chainName = + state.chain.registryName || + location.pathname.split("/")[1] || + process.env.NEXT_PUBLIC_REGISTRY_NAME || + "cosmoshub"; + + const isTestnet = !!state.chains.testnets.find(({ name }) => name === chainName); + + try { + const chainFromRegistry = await getChainFromRegistry(chainName, isTestnet); + setChain(dispatch, chainFromRegistry); + } catch (error) { + if (error instanceof Error) { + setChainsError(dispatch, error.message); + } else { + setChainsError(dispatch, "Failed to get chains from registry"); + } + } + } + })(); + }, [ + state.chain.chainId, + state.chain.registryName, + state.chains.mainnets.length, + state.chains.testnets, + ]); + + return {children}; +}; + +export const useChains = () => { + const context = useContext(ChainsContext); + if (context === undefined) { + throw new Error("useChains must be used within a ChainsProvider"); + } + return { ...context.state, chainsDispatch: context.dispatch }; +};