Skip to content

Commit

Permalink
Add navigation provider
Browse files Browse the repository at this point in the history
  • Loading branch information
tschumpr committed Jan 15, 2025
1 parent 5126a2d commit 1a19a8f
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 95 deletions.
89 changes: 46 additions & 43 deletions src/Geopilot.Frontend/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Imprint } from "./pages/footer/imprint.tsx";
import { DeliveryProvider } from "./pages/delivery/deliveryContext.tsx";
import { CircularProgress } from "@mui/material";
import MandateDetail from "./pages/admin/mandateDetail.tsx";
import { ControlledNavigateProvider } from "./components/controlledNavigate/controlledNavigateProvider.tsx";

export const App: FC = () => {
const [isSubMenuOpen, setIsSubMenuOpen] = useState(false);
Expand All @@ -25,49 +26,51 @@ export const App: FC = () => {
return (
<AppBox>
<BrowserRouter>
<Header
openSubMenu={() => {
setIsSubMenuOpen(true);
}}
/>
<LayoutBox>
<PageContentBox>
{isLoading ? (
<CircularProgress />
) : (
<Routes>
<Route
path="/"
element={
<DeliveryProvider>
<Delivery />
</DeliveryProvider>
}
/>
{isAdmin ? (
<>
<Route path="admin" element={<Navigate to="/admin/delivery-overview" replace />} />
<Route
path="admin"
element={<Admin isSubMenuOpen={isSubMenuOpen} setIsSubMenuOpen={setIsSubMenuOpen} />}>
<Route path="delivery-overview" element={<DeliveryOverview />} />
<Route path="users" element={<Users />} />
<Route path="mandates" element={<Mandates />} />
<Route path="mandates/:id" element={<MandateDetail />} />
<Route path="organisations" element={<Organisations />} />
</Route>
</>
) : (
<Route path="admin/*" element={<Navigate to="/" replace />} />
)}
<Route path="/imprint" element={<Imprint />} />
<Route path="/privacy-policy" element={<PrivacyPolicy />} />
<Route path="/about" element={<About />} />
</Routes>
)}
</PageContentBox>
<Footer />
</LayoutBox>
<ControlledNavigateProvider>
<Header
openSubMenu={() => {
setIsSubMenuOpen(true);
}}
/>
<LayoutBox>
<PageContentBox>
{isLoading ? (
<CircularProgress />
) : (
<Routes>
<Route
path="/"
element={
<DeliveryProvider>
<Delivery />
</DeliveryProvider>
}
/>
{isAdmin ? (
<>
<Route path="admin" element={<Navigate to="/admin/delivery-overview" replace />} />
<Route
path="admin"
element={<Admin isSubMenuOpen={isSubMenuOpen} setIsSubMenuOpen={setIsSubMenuOpen} />}>
<Route path="delivery-overview" element={<DeliveryOverview />} />
<Route path="users" element={<Users />} />
<Route path="mandates" element={<Mandates />} />
<Route path="mandates/:id" element={<MandateDetail />} />
<Route path="organisations" element={<Organisations />} />
</Route>
</>
) : (
<Route path="admin/*" element={<Navigate to="/" replace />} />
)}
<Route path="/imprint" element={<Imprint />} />
<Route path="/privacy-policy" element={<PrivacyPolicy />} />
<Route path="/about" element={<About />} />
</Routes>
)}
</PageContentBox>
<Footer />
</LayoutBox>
</ControlledNavigateProvider>
</BrowserRouter>
</AppBox>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { createContext, FC, PropsWithChildren, useState } from "react";
import { useNavigate } from "react-router-dom";

export const ControlledNavigateContext = createContext({
// eslint-disable-next-line @typescript-eslint/no-unused-vars
navigateTo: (path: string) => {},
checkIsDirty: false,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
registerCheckIsDirty: (path: string) => {},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
unregisterCheckIsDirty: (path: string) => {},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
leaveEditingPage: (canLeave: boolean) => {},
});

export const ControlledNavigateProvider: FC<PropsWithChildren> = ({ children }) => {
const [path, setPath] = useState<string>();
const [registeredEditPages, setRegisteredEditPages] = useState<string[]>([]);
const [checkIsDirty, setCheckIsDirty] = useState<boolean>(false);
const navigate = useNavigate();

const registerCheckIsDirty = (path: string) => {
if (!registeredEditPages.includes(path)) {
setRegisteredEditPages([...registeredEditPages, path]);
}
};

const unregisterCheckIsDirty = (path: string) => {
setRegisteredEditPages(registeredEditPages.filter(value => value !== path));
};

const navigateTo = (path: string) => {
if (
registeredEditPages.find(value => {
return window.location.pathname.includes(value);
})
) {
setPath(path);
setCheckIsDirty(true);
} else {
navigate(path);
}
};

const leaveEditingPage = (canLeave: boolean) => {
if (canLeave && path) {
navigate(path);
}
setCheckIsDirty(false);
setPath(undefined);
};

return (
<ControlledNavigateContext.Provider
value={{
navigateTo,
registerCheckIsDirty,
unregisterCheckIsDirty,
checkIsDirty,
leaveEditingPage,
}}>
{children}
</ControlledNavigateContext.Provider>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { useContext } from "react";
import { ControlledNavigateContext } from "./controlledNavigateProvider.tsx";

export const useControlledNavigate = () => useContext(ControlledNavigateContext);
11 changes: 6 additions & 5 deletions src/Geopilot.Frontend/src/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useTranslation } from "react-i18next";
import { FC, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { useLocation } from "react-router-dom";
import {
AppBar,
Avatar,
Expand All @@ -25,14 +25,15 @@ import { LanguagePopup } from "./languagePopup";
import MenuIcon from "@mui/icons-material/Menu";
import { FlexRowBox, FlexSpaceBetweenBox } from "../styledComponents.ts";
import { BaseButton } from "../buttons.tsx";
import { useControlledNavigate } from "../controlledNavigate";

interface HeaderProps {
openSubMenu: () => void;
}

const Header: FC<HeaderProps> = ({ openSubMenu }) => {
const { t } = useTranslation();
const navigate = useNavigate();
const { navigateTo } = useControlledNavigate();
const location = useLocation();
const { clientSettings } = useAppSettings();
const { user, authEnabled, isAdmin, login, logout } = useGeopilotAuth();
Expand Down Expand Up @@ -64,7 +65,7 @@ const Header: FC<HeaderProps> = ({ openSubMenu }) => {
data-cy="header"
sx={{ padding: "5px 0", cursor: "pointer" }}
onClick={() => {
navigate("/");
navigateTo("/");
}}>
<Box sx={{ display: { xs: "block", md: "none" }, flex: "0", marginRight: "10px" }}>
{hasSubMenu ? (
Expand Down Expand Up @@ -165,7 +166,7 @@ const Header: FC<HeaderProps> = ({ openSubMenu }) => {
<ListItemButton
selected={isActive("")}
onClick={() => {
navigate("/");
navigateTo("/");
}}
data-cy="delivery-nav">
<ListItemText primary={t("delivery").toUpperCase()} />
Expand All @@ -177,7 +178,7 @@ const Header: FC<HeaderProps> = ({ openSubMenu }) => {
<ListItemButton
selected={isActive("admin")}
onClick={() => {
navigate("/admin");
navigateTo("/admin");
}}
data-cy="admin-nav">
<ListItemText primary={t("administration").toUpperCase()} />
Expand Down
13 changes: 7 additions & 6 deletions src/Geopilot.Frontend/src/pages/admin/admin.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useTranslation } from "react-i18next";
import { Box, Divider, Drawer, List, ListItem, ListItemButton, ListItemText, Typography } from "@mui/material";
import { FC } from "react";
import { Outlet, useNavigate } from "react-router-dom";
import { Outlet } from "react-router-dom";
import { useAppSettings } from "../../components/appSettings/appSettingsInterface.ts";
import { FlexRowBox } from "../../components/styledComponents.ts";
import { useControlledNavigate } from "../../components/controlledNavigate";

interface AdminProps {
isSubMenuOpen: boolean;
Expand All @@ -12,15 +13,15 @@ interface AdminProps {

const Admin: FC<AdminProps> = ({ isSubMenuOpen, setIsSubMenuOpen }) => {
const { t } = useTranslation();
const navigate = useNavigate();
const { navigateTo } = useControlledNavigate();
const { clientSettings } = useAppSettings();

const handleDrawerClose = () => {
setIsSubMenuOpen(false);
};

const navigateTo = (path: string) => {
navigate(path);
const navigate = (path: string) => {
navigateTo(path);
if (isSubMenuOpen) {
handleDrawerClose();
}
Expand All @@ -42,7 +43,7 @@ const Admin: FC<AdminProps> = ({ isSubMenuOpen, setIsSubMenuOpen }) => {
<ListItemButton
selected={isActive("delivery-overview")}
onClick={() => {
navigateTo("delivery-overview");
navigate("/admin/delivery-overview");
}}
data-cy="admin-delivery-overview-nav">
<ListItemText primary={t("deliveryOverview").toUpperCase()} />
Expand All @@ -56,7 +57,7 @@ const Admin: FC<AdminProps> = ({ isSubMenuOpen, setIsSubMenuOpen }) => {
<ListItemButton
selected={isActive(link)}
onClick={() => {
navigateTo(link);
navigate("/admin/" + link);
}}
data-cy={`admin-${link}-nav`}>
<ListItemText primary={t(link).toUpperCase()} />
Expand Down
Loading

0 comments on commit 1a19a8f

Please sign in to comment.