From a4fa921ad1c72ec7313b461ddf1e8b4b311eedd1 Mon Sep 17 00:00:00 2001 From: frostyfan109 Date: Thu, 16 Nov 2023 20:55:09 -0500 Subject: [PATCH] Changes to header menu and routing --- src/components/layout/layout.js | 44 +++++++++++++++++++++++++++-- src/contexts/environment-context.js | 14 ++++++--- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/components/layout/layout.js b/src/components/layout/layout.js index 7d49b0c9..ec225295 100644 --- a/src/components/layout/layout.js +++ b/src/components/layout/layout.js @@ -31,14 +31,49 @@ export const Layout = ({ children }) => { setLoggingOut(false) } const removeTrailingSlash = (url) => url.endsWith("/") ? url.slice(0, url.length - 1) : url + const getRouteAncestors = (route, ancestors=[]) => { + if (!route.parent) return ancestors + const parent = routes.find((r) => r.path === route.parent) + return getRouteAncestors(parent, [...ancestors, parent]) + } + const makeMenuRoute = (route, props, children=undefined) => ({ + key: route.path, + label: ( + {route.text} + ), + children, + ...props + }) + const generateMenuRoute = (route) => { + // We don't include any routes text as menu items + if (!route.text) return null + // If the route is not a submenu, include it as a top-level menu item + if (!route.subMenu) return makeMenuRoute(route) + // Route is a submenu, include children routes as well. + const childrenRoutes = routes.filter((r) => r.text && r.parent === route.path) + // The submenus looked really bad, removing for the time being. + return makeMenuRoute(route) + // return makeMenuRoute(route, {}, childrenRoutes.map((c) => generateMenuRoute(c)).filter((r) => r !== null)) + } + const menuRoutes = [ + // These 3 empty items are a legacy styling thing that affect spacing. + makeMenuRoute({}, { key: 0, style: { visibility: "hidden" } }), + makeMenuRoute({}, { key: 1, style: { visibility: "hidden" } }), + makeMenuRoute({}, { key: 2, style: { visibility: "hidden" } }), + ...routes.filter((r) => r.text && !r.parent).map((route) => generateMenuRoute(route)), + ] + /** + * 1) Find the routes whose paths exactly match the current URL path + * 2) Also include all parents of routes whose paths are matched in (1) + */ const activeRoutes = routes.filter((route) => ( // route.text !== "" && removeTrailingSlash(`${baseLinkPath}${route.path}`) === removeTrailingSlash(location.pathname) )).flatMap((route) => ([ route, - ...routes.filter((m) => m.path === route.parent) + ...getRouteAncestors(route) ])).map((route) => route.path) - + console.log(menuRoutes, activeRoutes) return (
@@ -50,13 +85,16 @@ export const Layout = ({ children }) => { theme="light" mode="horizontal" selectedKeys={activeRoutes} + items={ menuRoutes } style={{ display: "flex", flexGrow: 1, justifyContent: "flex-end" }} > {routes.map(m => m['text'] !== '' && ( - {m.text} + + {m.text} + ))} {context.workspaces_enabled && !apiLoading && ( appstoreContext.links.map((link) => ( diff --git a/src/contexts/environment-context.js b/src/contexts/environment-context.js index 96fe0863..09c67fc7 100644 --- a/src/contexts/environment-context.js +++ b/src/contexts/environment-context.js @@ -10,6 +10,7 @@ import { SearchView, SplashScreenView, WorkspaceSignupView, + EduhelxAssignmentView } from '../views' // Setup global csrf token @@ -43,7 +44,7 @@ export const EnvironmentProvider = ({ children }) => { // If workspace module is enabled, all relevant paths will be added. (/workspaces/active, workspace/available, ...) // Note: `parent` property refers to another equivalent or encapsulating route that occupies an entry in the site's header. // It's important to include this if applicable so that the header entry stays active, e.g. on subroutes of workspaces. - const generateRoutes = (searchEnabled, workspaceEnabled) => { + const generateRoutes = (searchEnabled, workspaceEnabled, isEduhelx) => { const baseRoutes = []; if (searchEnabled === 'true') { // route homepage to search if search is enabled @@ -55,13 +56,18 @@ export const EnvironmentProvider = ({ children }) => { if (searchEnabled === 'false') { baseRoutes.push({ path: '/', parent: '/workspaces', text: '', Component: AvailableView }) } - baseRoutes.push({ path: '/workspaces', text: 'Workspaces', Component: AvailableView }) + baseRoutes.push({ path: '/workspaces', text: 'Workspaces', subMenu: true, Component: AvailableView }) baseRoutes.push({ path: '/workspaces/login', parent: '/workspaces', text: '', Component: WorkspaceLoginView }) baseRoutes.push({ path: '/workspaces/login/success', parent: '/workspaces', text: '', Component: LoginSuccessRedirectView }) baseRoutes.push({ path: '/workspaces/signup/social', parent: '/workspaces', text: '', Component: WorkspaceSignupView }) baseRoutes.push({ path: '/workspaces/available', parent: '/workspaces', text: '', Component: AvailableView }) - baseRoutes.push({ path: '/workspaces/active', parent: '/workspaces', text: '', Component: ActiveView }) + baseRoutes.push({ path: '/workspaces/active', parent: '/workspaces', text: 'Active', Component: ActiveView }) baseRoutes.push({ path: '/connect/:app_name/:app_url', parent: '/workspaces', text: '', Component: SplashScreenView }) + + if (isEduhelx) { + baseRoutes.push({ path: '/workspaces/edu', parent: '/workspaces', subMenu: true, text: 'Eduhelx', Component: () => null }) + baseRoutes.push({ path: '/workspaces/edu/assignment', parent: '/workspaces/edu', text: 'Assignments', Component: EduhelxAssignmentView }) + } } if (searchEnabled === 'false' && workspaceEnabled === 'false') { // route homepage to support page if both search and workspaces are disabled @@ -106,7 +112,7 @@ export const EnvironmentProvider = ({ children }) => { // If workspace is enabled, all routes should have a '/helx' basePath as the ui is embedded in the appstore useEffect(() => { if (Object.keys(context).length !== 0) { - const routes = generateRoutes(context.search_enabled, context.workspaces_enabled); + const routes = generateRoutes(context.search_enabled, context.workspaces_enabled, context.brand === "eduhelx"); setAvailableRoutes(routes); if (context.workspaces_enabled === 'true') { setBasePath('/helx/');