Skip to content

Commit

Permalink
Merge pull request #27 from bcgov/set-up-breadcrumb-nav
Browse files Browse the repository at this point in the history
Set up breadcrumb nav
  • Loading branch information
jadmsaadaot authored Aug 13, 2024
2 parents 3bee952 + 0fd9d0f commit 00df2d3
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 127 deletions.
113 changes: 0 additions & 113 deletions submit-web/src/components/Shared/SideNavBar.tsx

This file was deleted.

73 changes: 73 additions & 0 deletions submit-web/src/components/Shared/layout/SideNav/BreadcrumbNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from "react";
import { Box, Breadcrumbs, Typography } from "@mui/material";
import { Link, useRouterState } from "@tanstack/react-router";
import { theme } from "@/styles/theme";

interface RouteSegment {
title: string;
path: string;
}

const filterUniqueRoutes = (breadcrumbs: RouteSegment[]) => {
const seenPaths = new Set();
return breadcrumbs.filter((segment) => {
const isUnique = !seenPaths.has(segment.path);
if (isUnique) {
seenPaths.add(segment.path);
}
return isUnique;
});
};

const BreadcrumbNav: React.FC = () => {
const router = useRouterState();
const breadcrumbs = router.matches.map((match) => {
const { meta, pathname } = match;
if (meta)
return {
title: meta[0].title,
path: pathname,
};
});

const uniqueBreadcrumbs = filterUniqueRoutes(breadcrumbs as RouteSegment[]);
const isRoot = uniqueBreadcrumbs.length === 1;

return (
<>
{!isRoot && (
<Box
sx={{
p: 1,
paddingLeft: 5,
borderBottom: "1px solid #0000001A",
}}
>
<Breadcrumbs aria-label="breadcrumb">
{uniqueBreadcrumbs.map(
(segment: { title: string; path: string }, index: number) => {
const { title, path } = segment;
const isLast = index === uniqueBreadcrumbs.length - 1;
return isLast ? (
<Typography key={path} color="text.primary">
{title}
</Typography>
) : (
<Link
key={path}
style={{ color: theme.palette.primary.dark }}
to={path}
>
{title}
</Link>
);
}
)}
</Breadcrumbs>
</Box>
)}
</>
);
};

export default BreadcrumbNav;
131 changes: 131 additions & 0 deletions submit-web/src/components/Shared/layout/SideNav/SideNavBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { useState } from "react";
import {
Box,
List,
ListItem,
ListItemButton,
ListItemText,
} from "@mui/material";
import { Link } from "@tanstack/react-router";
import { theme } from "@/styles/theme";
import { useAuth } from "react-oidc-context";
import { AuthenticatedRoutes, Routes } from "./SideNavElements";
import { alpha } from "@mui/system";
import { useIsMobile } from "@/hooks/common";

export default function SideNavBar() {
const { isAuthenticated } = useAuth();
const [currentPath, setCurrentPath] = useState(window.location.pathname);
const isMobile = useIsMobile();

let routeMenuItems = Routes;

if (isAuthenticated) {
routeMenuItems = routeMenuItems.concat(AuthenticatedRoutes);
}

return (
<div>
{!isMobile && (
<Box
sx={{
overflow: "auto",
borderRight: "1px solid #0000001A",
width: 240,
height: "calc(100vh - 88px)",
zIndex: 0,
position: "static",
}}
>
<List>
{routeMenuItems.map((route) => (
<>
<ListItem key={route.name}>
<Link
to={route.path}
onClick={() => setCurrentPath(route.path)}
style={{
color: theme.palette.primary.light,
fontWeight: "bold",
textDecoration: "none",
width: "100%",
}}
>
<ListItemButton
sx={{
pl: "2rem",
backgroundColor:
currentPath === route.path
? alpha(theme.palette.secondary.main, 0.1)
: theme.palette.primary.light,
borderLeft: `4px solid ${theme.palette.primary.main}`,
}}
>
<span
style={{
color: alpha(theme.palette.primary.main, 0.8),
}}
>
{route.name}
</span>
</ListItemButton>
</Link>
</ListItem>
{route.routes && route.routes?.length > 0 && (
<List disablePadding key={`list-${route.name}`}>
{route.routes?.map((subRoute) => (
<ListItem
key={`sub-list-${subRoute?.name}`}
sx={{ margin: 0, padding: 0 }}
>
<Link
to={subRoute.path}
onClick={() => setCurrentPath(subRoute.path)}
style={{
textDecoration: "none",
margin: 0,
padding: 0,
color: "inherit",
}}
activeProps={{
style: {
color: theme.palette.primary.main,
fontWeight:
currentPath === subRoute.path
? "bold"
: "normal",
width: "100%",
},
}}
>
<ListItemButton
key={`sub-list-button-${subRoute?.name}`}
sx={{
marginLeft: "40px",
borderLeft:
currentPath === subRoute.path
? `4px solid ${theme.palette.primary.main}`
: `1px solid ${theme.palette.divider}`,
}}
>
<ListItemText
key={`sub-list-text-${subRoute?.name}`}
>
<span style={{ color: "inherit" }}>
{subRoute.name}
</span>
</ListItemText>
</ListItemButton>
</Link>
</ListItem>
))}
</List>
)}
</>
))}
</List>
</Box>
)}
</div>
);
}
8 changes: 8 additions & 0 deletions submit-web/src/hooks/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useMediaQuery, useTheme } from "@mui/material";

export const useIsMobile = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));

return isMobile;
};
16 changes: 14 additions & 2 deletions submit-web/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import EAOAppBar from "@/components/Shared/EAOAppBar";
import Footer from "@/components/Shared/layout/Footer";
import PageNotFound from "@/components/Shared/PageNotFound";
import SideNavBar from "@/components/Shared/layout/SideNav/SideNavBar";
import { Box } from "@mui/system";
import { createRootRouteWithContext, Outlet } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/router-devtools";
import { AuthContextProps } from "react-oidc-context";
import { AuthContextProps, useAuth } from "react-oidc-context";
import { useIsMobile } from "@/hooks/common";
import BreadcrumbNav from "@/components/Shared/layout/SideNav/BreadcrumbNav";

type RouterContext = {
authentication: AuthContextProps;
Expand All @@ -13,15 +16,24 @@ type RouterContext = {
export const Route = createRootRouteWithContext<RouterContext>()({
component: Layout,
notFoundComponent: PageNotFound,
meta: () => [{ title: "Home" }],
});

function Layout() {
const { isAuthenticated } = useAuth();
const isMobile = useIsMobile();
return (
<>
<EAOAppBar />
{isAuthenticated && <BreadcrumbNav />}
<Box
height={"calc(100vh - 88px)"}
width={
isMobile ? "100%" : `calc(100vw - ${isAuthenticated ? 240 : 0}px)`
}
flexDirection={isAuthenticated ? "column" : "row"}
display={"flex"}
>
{isAuthenticated && <SideNavBar />}
<Outlet />
</Box>
<Footer />
Expand Down
1 change: 1 addition & 0 deletions submit-web/src/routes/_authenticated/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useAuth } from "react-oidc-context";

export const Route = createFileRoute("/_authenticated/profile")({
component: Profile,
meta: () => [{ title: "Profile" }],
});

function Profile() {
Expand Down
1 change: 1 addition & 0 deletions submit-web/src/routes/_authenticated/projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/_authenticated/projects/")({
component: ProjectsPage,
meta: () => [{ title: "Projects" }],
});

function ProjectsPage() {
Expand Down
Loading

0 comments on commit 00df2d3

Please sign in to comment.