diff --git a/packages/admin-ui/package.json b/packages/admin-ui/package.json index b8fc70d15..6630e8390 100644 --- a/packages/admin-ui/package.json +++ b/packages/admin-ui/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@dappnode/common": "^0.1.0", - "@dappnode/eventbus": "^0.1.0", "@dappnode/dappmanager": "^0.1.0", + "@dappnode/eventbus": "^0.1.0", "@dappnode/types": "^0.1.25", "@reduxjs/toolkit": "^1.3.5", "@types/clipboard": "^2.0.7", diff --git a/packages/admin-ui/src/App.tsx b/packages/admin-ui/src/App.tsx index 31e08d116..c13fdbe6a 100644 --- a/packages/admin-ui/src/App.tsx +++ b/packages/admin-ui/src/App.tsx @@ -9,62 +9,63 @@ import Loading from "components/Loading"; import Welcome from "components/welcome/Welcome"; import SideBar from "components/sidebar/SideBar"; import { TopBar } from "components/topbar/TopBar"; +import { rootPath as dashboardRootPath } from "./pages/dashboard"; // Pages import { pages } from "./pages"; import { Login } from "./start-pages/Login"; import { Register } from "./start-pages/Register"; import { NoConnection } from "start-pages/NoConnection"; // Types -import { Theme, UsageMode } from "types"; +import { AppContextIface } from "types"; -export const UsageContext = React.createContext({ - usage: "advanced", - toggleUsage: () => {} -}); - -export const ThemeContext = React.createContext({ +export const AppContext = React.createContext({ theme: "light", - toggleTheme: () => {} + stakersModuleStatus: "enabled", + rollupsModuleStatus: "disabled", + toggleTheme: () => {}, + toggleStakersModuleStatus: () => {}, + toggleRollupsModuleStatus: () => {} }); +const useLocalStorage = (key: string, initialValue: string) => { + const [storedValue, setStoredValue] = useState(() => { + try { + const item = window.localStorage.getItem(key); + return item ? JSON.parse(item) : initialValue; + } catch (error) { + return initialValue; + } + }); + + useEffect(() => { + window.localStorage.setItem(key, JSON.stringify(storedValue)); + }, [key, storedValue]); + + return [storedValue, setStoredValue]; +}; + function MainApp({ username }: { username: string }) { // App is the parent container of any other component. // If this re-renders, the whole app will. So DON'T RERENDER APP! // Check ONCE what is the status of the VPN and redirect to the login page. - const [screenWidth, setScreenWidth] = useState(window.screen.width); - - //const storedUsage = localStorage.getItem("usage"); - const storedTheme = localStorage.getItem("theme"); - //const initialUsage = storedUsage === "advanced" ? "advanced" : "basic"; - const initialUsage = "advanced"; - const initialTheme = - storedTheme === "light" || storedTheme === "dark" ? storedTheme : "light"; - - const [theme, setTheme] = useState(initialTheme); - const [usage, setUsage] = useState(initialUsage); - - const toggleTheme = () => { - setTheme(curr => (curr === "light" ? "dark" : "light")); - }; - - const toggleUsage = () => { - setUsage(curr => (curr === "basic" ? "advanced" : "basic")); - }; - - useEffect(() => { - localStorage.setItem("theme", theme); - }, [theme]); - - useEffect(() => { - localStorage.setItem("usage", usage); - }, [usage]); + const [screenWidth, setScreenWidth] = useState(window.innerWidth); + const [theme, setTheme] = useLocalStorage("theme", "light"); + const [usage, setUsage] = useLocalStorage("usage", "advanced"); + const [stakersModuleStatus, setStakersModuleStatus] = useLocalStorage( + "stakersModuleStatus", + "enabled" + ); + const [rollupsModuleStatus, setRollupsModuleStatus] = useLocalStorage( + "rollupsModuleStatus", + "disabled" + ); useEffect(() => { const handleResize = () => setScreenWidth(window.innerWidth); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); - }, [screenWidth]); + }, []); // Scroll to top on pathname change const screenLocation = useLocation(); @@ -72,23 +73,62 @@ function MainApp({ username }: { username: string }) { window.scrollTo(0, 0); }, [screenLocation.pathname]); + const contextValue = { + theme, + usage, + stakersModuleStatus, + rollupsModuleStatus, + toggleTheme: () => + setTheme((curr: string) => (curr === "light" ? "dark" : "light")), + toggleUsage: () => + setUsage((curr: string) => (curr === "basic" ? "advanced" : "basic")), + toggleStakersModuleStatus: () => + setStakersModuleStatus((curr: string) => + curr === "enabled" ? "disabled" : "enabled" + ), + toggleRollupsModuleStatus: () => + setRollupsModuleStatus((curr: string) => + curr === "enabled" ? "disabled" : "enabled" + ) + }; + return ( - - -
- - -
- - - - - {Object.values(pages).map(({ RootComponent, rootPath }) => ( + +
+ + +
+ + + + + {/** Provide the app context only to the dashboard (where the modules switch is handled) */} + {Object.values(pages).map(({ RootComponent, rootPath }) => + rootPath === dashboardRootPath ? ( + + + + } + /> + ) : ( } /> - ))} - {/* Redirection for routes with hashes */} - {/* 404 routes redirect to dashboard or default page */} - } /> - -
- - {/* Place here non-page components */} - - + ) + )} + {/* Redirection for routes with hashes */} + {/* 404 routes redirect to dashboard or default page */} + } /> +
- - + + {/* Place here non-page components */} + + +
+ ); } diff --git a/packages/admin-ui/src/__mock-backend__/index.ts b/packages/admin-ui/src/__mock-backend__/index.ts index ed55e15dc..438340e01 100644 --- a/packages/admin-ui/src/__mock-backend__/index.ts +++ b/packages/admin-ui/src/__mock-backend__/index.ts @@ -223,11 +223,11 @@ export const otherCalls: Omit = { ethProvider: "http://geth.dappnode:8545", fullnodeDomainTarget: "geth.dnp.dappnode.eth", newFeatureIds: [ - "repository", - "repository-fallback", - "system-auto-updates", - "enable-ethical-metrics", - "change-host-password" + //"repository", + //"repository-fallback", + //"system-auto-updates", + //"enable-ethical-metrics", + //"change-host-password" ] }), natRenewalEnable: async () => {}, diff --git a/packages/admin-ui/src/components/sidebar/SideBar.tsx b/packages/admin-ui/src/components/sidebar/SideBar.tsx index 903b6f6be..b465ce194 100644 --- a/packages/admin-ui/src/components/sidebar/SideBar.tsx +++ b/packages/admin-ui/src/components/sidebar/SideBar.tsx @@ -1,23 +1,26 @@ import React from "react"; import { NavLink } from "react-router-dom"; -import { advancedItems, basicItems, fundedBy } from "./navbarItems"; +import { sidenavItems, fundedBy } from "./navbarItems"; import logoWide from "img/dappnode-logo-wide-min.png"; import logoWideDark from "img/dappnode-logo-wide-min-dark.png"; import logomin from "img/dappnode-logo-only.png"; -import { ThemeContext, UsageContext } from "../../App"; +import { AppContext } from "../../App"; import "./sidebar.scss"; -if (!Array.isArray(advancedItems)) - throw Error("advancedItems must be an array"); -if (!Array.isArray(basicItems)) throw Error("basicItems must be an array"); +if (!Array.isArray(sidenavItems)) throw Error("sidenavItems must be an array"); if (!Array.isArray(fundedBy)) throw Error("fundedBy must be an array"); export default function SideBar({ screenWidth }: { screenWidth: number }) { - const { theme } = React.useContext(ThemeContext); - const { usage } = React.useContext(UsageContext); + const { theme, rollupsModuleStatus, stakersModuleStatus } = React.useContext( + AppContext + ); + + const stakersItem = sidenavItems.find(item => item.name === "Stakers"); + if (stakersItem) { + if (stakersModuleStatus === "enabled") stakersItem.show = true; + else stakersItem.show = false; + } - const sidenavItems = - usage === "advanced" ? [...basicItems, ...advancedItems] : basicItems; return (