diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 3a2ca4d..8c1713a 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -7,7 +7,6 @@ import MainContextProvider from "./contexts/mainContext";
import ProjectSheet from "./pages/projectSheet";
import DeploymentSheet from "./pages/deploymentSheet";
import DeviceMenuPage from "./pages/deviceMenu";
-import DeviceSheet from "./components/deviceSheet/deviceSheetMain";
import DeviceSheetPage from "./pages/deviceSheet";
import { theme } from "./theme";
import { LinearProgress, ThemeProvider } from "@mui/material";
@@ -18,9 +17,9 @@ import SiteMenuPage from "./pages/siteMenu";
import SiteSheetPage from "./pages/siteSheet";
import SnackContextProvider from "./contexts/snackContext";
import { AuthContext } from "./contexts/AuthContextProvider";
-import { useContext } from "react";
+import { useContext} from "react";
import FilesContextProvider from "./contexts/filesContext";
-;
+import RouteWrapper from "./components/RouteWrapper";
// Env var processed by nginx
OpenAPI.BASE = window._env_.REACT_APP_API_PATH || "/api/v1";
@@ -39,43 +38,103 @@ function App() {
- }>
- {/* }> */}
+
+
+
+ }
+ />
+ {/* } /> */}
}
- >
- }>
- }>
+ element={
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
+ element={
+
+
+
+ }
+ />
}
- >
- }>
+ element={
+
+
+
+ }
+ />
+
+
+
+ }
+ />
diff --git a/frontend/src/components/RouteWrapper.tsx b/frontend/src/components/RouteWrapper.tsx
new file mode 100644
index 0000000..43d821e
--- /dev/null
+++ b/frontend/src/components/RouteWrapper.tsx
@@ -0,0 +1,16 @@
+import { useRefreshToken } from "../hooks/useRefreshToken";
+
+/**
+ * A wrapper around the element rendered by the React Router component.
+ *
+ * Useful to trigger code when the route changes.
+ */
+const RouteWrapper = ({children}: {children: React.ReactNode}) => {
+ useRefreshToken();
+
+ return (
+ <>{children}>
+ );
+}
+
+export default RouteWrapper;
diff --git a/frontend/src/hooks/useRefreshToken.ts b/frontend/src/hooks/useRefreshToken.ts
new file mode 100644
index 0000000..e4f9cee
--- /dev/null
+++ b/frontend/src/hooks/useRefreshToken.ts
@@ -0,0 +1,40 @@
+import { useState, useEffect, useContext } from 'react';
+import { useLocation } from 'react-router-dom';
+
+import { OpenAPI } from '../client';
+import { AuthContext } from '../contexts/AuthContextProvider';
+import keycloak from '../keycloak';;
+
+
+const TOKEN_MIN_VALIDITY = 120;
+
+
+export const useRefreshToken = () => {
+ const [pending, setPending] = useState(true);
+ const location = useLocation();
+ const { logout } = useContext(AuthContext);
+
+ const onTokenRefresh = (token: string | undefined) => {
+ if (token) {
+ OpenAPI.TOKEN = token;
+ }
+ }
+
+ useEffect(() => {
+ const refreshToken = async () => {
+ try {
+ const refreshed = await keycloak.updateToken(TOKEN_MIN_VALIDITY);
+ if (refreshed) {
+ onTokenRefresh(keycloak.token);
+ }
+ setPending(false);
+ } catch (error) {
+ logout();
+ }
+ }
+
+ refreshToken();
+ }, [location]);
+
+ return { pending };
+};