Skip to content

Commit

Permalink
add modules context
Browse files Browse the repository at this point in the history
  • Loading branch information
pablomendezroyo committed Sep 20, 2023
1 parent 4d05aeb commit 05e2984
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 109 deletions.
2 changes: 1 addition & 1 deletion packages/admin-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
168 changes: 104 additions & 64 deletions packages/admin-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,86 +9,126 @@ 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<AppContextIface>({
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<Theme>(initialTheme);
const [usage, setUsage] = useState<UsageMode>(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();
useEffect(() => {
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 (
<UsageContext.Provider value={{ usage, toggleUsage }}>
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<div className="body" id={theme}>
<SideBar screenWidth={screenWidth} />
<TopBar
username={username}
theme={theme}
toggleUsage={toggleUsage}
toggleTheme={toggleTheme}
/>
<div id="main">
<ErrorBoundary>
<NotificationsMain />
</ErrorBoundary>
<Routes>
{Object.values(pages).map(({ RootComponent, rootPath }) => (
<AppContext.Provider value={contextValue}>
<div className="body" id={theme}>
<SideBar screenWidth={screenWidth} />
<TopBar
username={username}
theme={theme}
toggleUsage={contextValue.toggleUsage}
toggleTheme={contextValue.toggleTheme}
/>
<div id="main">
<ErrorBoundary>
<NotificationsMain />
</ErrorBoundary>
<Routes>
{/** Provide the app context only to the dashboard (where the modules switch is handled) */}
{Object.values(pages).map(({ RootComponent, rootPath }) =>
rootPath === dashboardRootPath ? (
<Route
key={rootPath}
path={rootPath}
element={
<ErrorBoundary>
<RootComponent
modulesContext={{
stakersModuleStatus: contextValue.stakersModuleStatus,
rollupsModuleStatus: contextValue.rollupsModuleStatus,
toggleStakersModuleStatus:
contextValue.toggleStakersModuleStatus,
toggleRollupsModuleStatus:
contextValue.toggleRollupsModuleStatus
}}
/>
</ErrorBoundary>
}
/>
) : (
<Route
key={rootPath}
path={rootPath}
Expand All @@ -98,19 +138,19 @@ function MainApp({ username }: { username: string }) {
</ErrorBoundary>
}
/>
))}
{/* Redirection for routes with hashes */}
{/* 404 routes redirect to dashboard or default page */}
<Route path="*" element={<DefaultRedirect />} />
</Routes>
</div>

{/* Place here non-page components */}
<Welcome />
<ToastContainer />
)
)}
{/* Redirection for routes with hashes */}
{/* 404 routes redirect to dashboard or default page */}
<Route path="*" element={<DefaultRedirect />} />
</Routes>
</div>
</ThemeContext.Provider>
</UsageContext.Provider>

{/* Place here non-page components */}
<Welcome />
<ToastContainer />
</div>
</AppContext.Provider>
);
}

Expand Down
10 changes: 5 additions & 5 deletions packages/admin-ui/src/__mock-backend__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,11 @@ export const otherCalls: Omit<Routes, keyof typeof namedSpacedCalls> = {
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 () => {},
Expand Down
44 changes: 22 additions & 22 deletions packages/admin-ui/src/components/sidebar/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div id="sidebar">
<NavLink to={"/"}>
Expand All @@ -35,19 +38,16 @@ export default function SideBar({ screenWidth }: { screenWidth: number }) {
</NavLink>

<div className="nav">
{sidenavItems.map(item => (
<NavLink
key={item.name}
className="sidenav-item selectable"
to={item.href}
>
<item.icon />
{/* 640 px = 40 rem */}
{screenWidth > 640 && (
<span className="name svg-text">{item.name}</span>
)}
</NavLink>
))}
{sidenavItems
.filter(item => item.show === true)
.map(item => (
<NavLink className={`sidenav-item selectable`} to={item.href}>
<item.icon />
{screenWidth > 640 && (
<span className="name svg-text">{item.name}</span>
)}
</NavLink>
))}
</div>

{/* spacer keeps the funded-by section at the bottom (if possible) */}
Expand Down
22 changes: 22 additions & 0 deletions packages/admin-ui/src/components/sidebar/sidebar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,28 @@
}
}

/* Define the fade transition */
/* Slide & Fade Transition */

/* Slide & Fade Transition for nav-item */

.nav-item-enter,
.nav-item-exit-active {
opacity: 0;
transform: translateX(-100%);
}

.nav-item-enter-active,
.nav-item-exit {
opacity: 1;
transform: translateX(0);
}

.nav-item-enter-active,
.nav-item-exit-active {
transition: opacity 500ms ease-in, transform 500ms ease-in-out;
}

/*
* ============
* Sidenav-item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BsMoon } from "react-icons/bs";
import { FaSun } from "react-icons/fa";
import React from "react";
import "./dropdown.scss";
import { ThemeContext } from "App";
import { AppContext } from "App";
import Tooltip from "react-bootstrap/Tooltip";
import OverlayTrigger from "react-bootstrap/OverlayTrigger";

Expand All @@ -11,7 +11,7 @@ export default function ThemeSwitch({
}: {
toggleTheme: () => void;
}) {
const { theme } = React.useContext(ThemeContext);
const { theme } = React.useContext(AppContext);
return (
<div className="tn-dropdown">
<OverlayTrigger
Expand Down
Loading

0 comments on commit 05e2984

Please sign in to comment.