diff --git a/src/App.jsx b/src/App.jsx index d7598f82..fb6082a9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,12 @@ import { useEffect, useContext } from "react"; import CssBaseline from "@mui/material/CssBaseline"; -import { Box, ThemeProvider } from "@mui/material"; +import { Box, ThemeProvider, CircularProgress } from "@mui/material"; import { BrowserRouter as Router, Routes, Route, useLocation, + useNavigate } from "react-router-dom"; import theme from "./theme"; import PropTypes from "prop-types"; @@ -40,39 +41,72 @@ const PageContainer = ({ children }) => { ); }; +const ProtectedRoute = ({ children }) => { + const { user } = useContext(GlobalDataContext); + const navigate = useNavigate(); + + useEffect(() => { + if (!user) { + navigate('/login'); + } + }, [user, navigate]); + + return user ? children : null; +}; + function MainContent() { - const { setUserData } = useContext(GlobalDataContext); + const { setUserData, loading } = useContext(GlobalDataContext); + const navigate = useNavigate(); // eslint-disable-next-line no-unused-vars const [existingCookies, setCookie, removeCookie] = useCookies(['session']); useEffect(() => { (async () => { - const userSettings = JSON.parse( - localStorage.getItem(API_CONFIG.SESSION_DATA.SETTINGS) - ); + const userSettings = JSON.parse(localStorage.getItem(API_CONFIG.SESSION_DATA.SETTINGS)); if (userSettings) { try { const userData = await requestUserSettings(userSettings?.groupname); setUserData({ - name: userData["groupname"], - id: userData["orcid"], + name: userData['groupname'], + id: userData['orcid'], email: userData?.emails[0]?.email, - role: userData["own-role"], - groupname: userData["groupname"], - settings: userData, + role: userData['own-role'], + groupname: userData['groupname'], + settings: userData }); + navigate("/"); } catch (error) { console.error("Error fetching user settings:", error); localStorage.removeItem(API_CONFIG.SESSION_DATA.SETTINGS); localStorage.removeItem(API_CONFIG.SESSION_DATA.COOKIE); - removeCookie("session", { path: "/" }); + removeCookie('session', { path: '/' }); + // setErrors((prev) => ({ + // ...prev, + // auth: "Session expired. Please log in again.", + // })); } } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + if (loading) { + return ( +
+ +
+ ) + } + return ( - - + + + + + } /> - - + + + + + } /> - - + + + + + } /> - - + + + + + } /> @@ -219,6 +261,10 @@ PageContainer.propTypes = { children: PropTypes.node.isRequired, }; +ProtectedRoute.propTypes = { + children: PropTypes.node.isRequired, +}; + Layout.propTypes = { children: PropTypes.node.isRequired, }; diff --git a/src/components/Auth/Login.jsx b/src/components/Auth/Login.jsx index e583b4f9..2c6bac1e 100644 --- a/src/components/Auth/Login.jsx +++ b/src/components/Auth/Login.jsx @@ -41,37 +41,6 @@ const Login = () => { const { setUserData } = React.useContext(GlobalDataContext); const navigate = useNavigate(); - React.useEffect(() => { - (async () => { - const userSettings = JSON.parse(localStorage.getItem(API_CONFIG.SESSION_DATA.SETTINGS)); - if (userSettings) { - try { - const userData = await requestUserSettings(userSettings?.groupname); - setUserData({ - name: userData['groupname'], - id: userData['orcid'], - email: userData?.emails[0]?.email, - role: userData['own-role'], - groupname: userData['groupname'], - settings: userData - }); - navigate("/"); - } catch (error) { - console.error("Error fetching user settings:", error); - localStorage.removeItem(API_CONFIG.SESSION_DATA.SETTINGS); - localStorage.removeItem(API_CONFIG.SESSION_DATA.COOKIE); - removeCookie('session', { path: '/' }); - setErrors((prev) => ({ - ...prev, - auth: "Session expired. Please log in again.", - })); - } - } - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - React.useEffect(() => { let eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; let eventer = window[eventMethod]; diff --git a/src/components/Header/index.jsx b/src/components/Header/index.jsx index 538daf69..a29c0dc1 100644 --- a/src/components/Header/index.jsx +++ b/src/components/Header/index.jsx @@ -106,8 +106,8 @@ const styles = { }, avatar: { - border: '0.0469rem solid rgba(0,0,0,0.08)', - width: '2.5rem', + border: '0.0469rem solid rgba(0,0,0,0.08)', + width: '2.5rem', height: '2.5rem', '& .MuiSvgIcon-root': { width: '1.5rem', @@ -121,7 +121,8 @@ const NavMenu = [ { label: 'Organizations', icon: , - href: '/organizations' + href: '/organizations', + protected: true }, { label: 'Term activity', @@ -257,18 +258,22 @@ const Header = () => { return () => { document.removeEventListener('keydown', handleKeyDown); }; - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); React.useEffect(() => { console.log("Stored user in context ", user) - if(user !== null && user?.groupname !== undefined) { + if (user !== null && user?.groupname !== undefined) { setIsLoggedIn(true) } else { setIsLoggedIn(false) } }, [user]) + const filteredNavMenu = NavMenu.filter(menu => + !menu.protected || (menu.protected && isLoggedIn) + ); + return ( <> @@ -293,7 +298,7 @@ const Header = () => { }} > - {NavMenu.map((menu, index) => ( + {filteredNavMenu.map((menu, index) => ( handleMenuClick(e, menu)}> @@ -303,23 +308,25 @@ const Header = () => { ))} - - - - - - - - - - - - - - - - - + {isLoggedIn && (<> + + + + + + + + + + + + + + + + + + )} navigate("/")} style={{ cursor: 'pointer' }}> diff --git a/src/contexts/DataContext.jsx b/src/contexts/DataContext.jsx index 340a8abe..aecc7609 100644 --- a/src/contexts/DataContext.jsx +++ b/src/contexts/DataContext.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; -import {createContext, useState} from "react"; +import {createContext, useState, useEffect} from "react"; +import { API_CONFIG } from '../config'; const GlobalDataContext = createContext(); @@ -11,6 +12,7 @@ const GlobalDataProvider = ({ children }) => { const [predicatesSingleTermState, setPredicatesSingleTermState] = useState(false); const [editBulkSearchFilters, setEditBulkSearchFilters] = useState([]); const [storedSearchTerm, setStoredSearchTerm] = useState(""); + const [loading, setLoading] = useState(true); const setOntologyData = (ontology) => { setActiveOntology(ontology); }; @@ -39,6 +41,16 @@ const GlobalDataProvider = ({ children }) => { setStoredSearchTerm(value) } + useEffect(() => { + const userSettings = localStorage.getItem(API_CONFIG.SESSION_DATA.SETTINGS); + + if(userSettings) { + setUser(JSON.parse(userSettings)) + } + + setLoading(false) + }, []) + const dataContextValue = { user, setUserData, @@ -53,7 +65,8 @@ const GlobalDataProvider = ({ children }) => { editBulkSearchFilters, setEditBulkSearchData, storedSearchTerm, - updateStoredSearchTerm + updateStoredSearchTerm, + loading }; return (