From 2a1a57f2b61e75714bcccd64ecff2d9f7744a4bc Mon Sep 17 00:00:00 2001 From: Maithy Le Date: Mon, 4 Mar 2024 21:28:39 -0800 Subject: [PATCH] Set student view and updated role permissions (#47) Co-authored-by: Ethan Ho Co-authored-by: ThatMegamind <92563733+ThatMegamind@users.noreply.github.com> --- src/App.jsx | 34 +++++++---- src/common/AuthContext.jsx | 25 ++++++++ src/components/Navbar/Navbar.jsx | 61 ++++++++++++++++--- .../PublishedSchedule/PublishedSchedule.jsx | 22 ++++--- src/utils/ProtectedRoute.jsx | 16 +++-- src/utils/auth_config.js | 4 +- src/utils/auth_utils.js | 7 +-- 7 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 src/common/AuthContext.jsx diff --git a/src/App.jsx b/src/App.jsx index 3321d4a..7f6839b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -15,26 +15,29 @@ import PublishedSchedule from './pages/PublishedSchedule/PublishedSchedule'; import Playground from './pages/Playground/Playground'; import Planner from './pages/Planner/Planner'; import Navbar from './components/Navbar/Navbar'; -import { auth, getCurrentUser } from './utils/auth_utils'; import NotificationSandbox from './pages/NotificationSandbox/NotificationSandbox'; +import { AuthContextProvider, useAuthContext } from './common/AuthContext'; const { ADMIN_ROLE, USER_ROLE } = AUTH_ROLES.AUTH_ROLES; -const currentUser = getCurrentUser(auth); -console.log(currentUser); const App = () => { - const NavBarWrapper = () => ( - <> - - - - ); + const NavBarWrapper = () => { + const { currentUser } = useAuthContext(); + return ( + <> + + + + ); + }; + return ( + - : null}> + }> { } /> @@ -82,10 +85,17 @@ const App = () => { } /> } /> - } /> + + } /> + ); diff --git a/src/common/AuthContext.jsx b/src/common/AuthContext.jsx new file mode 100644 index 0000000..7d09983 --- /dev/null +++ b/src/common/AuthContext.jsx @@ -0,0 +1,25 @@ +/* eslint-disable react/jsx-no-constructed-context-values */ +import { createContext, useState, useContext } from 'react'; +import PropTypes from 'prop-types'; + +const AuthContext = createContext({ + currentUser: null, + setCurrentUser: () => {}, +}); + +const useAuthContext = () => { + return useContext(AuthContext); +}; + +const AuthContextProvider = ({ children }) => { + const [currentUser, setCurrentUser] = useState(null); + return ( + {children} + ); +}; + +AuthContextProvider.propTypes = { + children: PropTypes.node.isRequired, +}; + +export { useAuthContext, AuthContextProvider }; \ No newline at end of file diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index f07ef38..7f8a998 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -1,9 +1,12 @@ import { NavLink } from 'react-router-dom'; import { Flex, HStack, Link, Text, Image } from '@chakra-ui/react'; import { BellIcon } from '@chakra-ui/icons'; +import PropTypes from 'prop-types'; + import Logout from '../Authentication/Logout'; -const Navbar = () => { +const Navbar = ({ hasLoaded, isAdmin }) => { + // console.log(hasLoaded, isAdmin); const makeNavTabs = (page, path) => { const selectedTab = location.pathname == path; return ( @@ -28,7 +31,42 @@ const Navbar = () => { ); }; - return ( + + if (!hasLoaded) { + return null; + } + + if (isAdmin) { + return ( + + + + + {makeNavTabs('Schedule', '/publishedSchedule')} + {makeNavTabs('Catalog', '/catalog')} + + + + + + + + ) + } + return ( { {makeNavTabs('Schedule', '/publishedSchedule')} - {makeNavTabs('Catalog', '/catalog')} - + ); }; +Navbar.propTypes = { + hasLoaded: PropTypes.bool, + isAdmin: PropTypes.bool, +}; + +Navbar.defaultProps = { + hasLoaded: false, + isAdmin: false, +}; + export default Navbar; diff --git a/src/pages/PublishedSchedule/PublishedSchedule.jsx b/src/pages/PublishedSchedule/PublishedSchedule.jsx index 621ae6d..a731542 100644 --- a/src/pages/PublishedSchedule/PublishedSchedule.jsx +++ b/src/pages/PublishedSchedule/PublishedSchedule.jsx @@ -1,11 +1,15 @@ import { NPOBackend } from '../../utils/auth_utils.js'; import PublishedScheduleTable from '../../components/Events/PublishedScheduleTable.jsx'; +import AUTH_ROLES from '../../utils/auth_config.js'; +import { useAuthContext } from '../../common/AuthContext.jsx'; import { useEffect, useState } from 'react'; +const { ADMIN_ROLE, USER_ROLE } = AUTH_ROLES.AUTH_ROLES; import { Box, Select, Text } from '@chakra-ui/react'; const PublishedSchedule = () => { // get data from database + const {currentUser} = useAuthContext(); const [allSeasons, setAllSeasons] = useState([]); const [selectedSeason, setSelectedSeason] = useState(''); @@ -30,6 +34,9 @@ const PublishedSchedule = () => { useEffect(() => { const renderTable = async () => { const { data } = await NPOBackend.get('/published-schedule/all-seasons'); + + setSelectedSeason(currentUser.type === USER_ROLE ? data[0] : ''); // We assume the current season is the first one in the list + const index = data.indexOf(curSeason); if (index !== -1) { data.splice(index, 1); @@ -44,10 +51,12 @@ const PublishedSchedule = () => { return seasonOrder.indexOf(a.split(' ')[0]) - seasonOrder.indexOf(b.split(' ')[0]); } }); + setAllSeasons(data); + }; - renderTable(); - }, []); + renderTable(); + }, [currentUser]); const curSeason = getTodaySeason(); @@ -71,11 +80,10 @@ const PublishedSchedule = () => { onChange={() => setSelectedSeason(event.target.value)} width="23%" > - {allSeasons.map(item => ( - - ))} + { currentUser.type === ADMIN_ROLE ? + allSeasons.map(item => ( + + )) : null } {/* tables for each season */} diff --git a/src/utils/ProtectedRoute.jsx b/src/utils/ProtectedRoute.jsx index 3f0fbe9..df96844 100644 --- a/src/utils/ProtectedRoute.jsx +++ b/src/utils/ProtectedRoute.jsx @@ -3,17 +3,21 @@ import { Navigate } from 'react-router-dom'; import { PropTypes, instanceOf } from 'prop-types'; import { withCookies, cookieKeys, Cookies, clearCookies } from './cookie_utils'; import { NPOBackend, refreshToken } from './auth_utils'; +import { useAuthContext } from '../common/AuthContext'; const userIsAuthenticated = async (roles, cookies) => { try { - const accessToken = await refreshToken(cookies); + const { accessToken, currentUser } = await refreshToken(cookies); + // const accessToken = await refreshToken(cookies); if (!accessToken) { return false; } const loggedIn = await NPOBackend.get(`/auth/verifyToken/${accessToken}`); - return roles.includes(cookies.get(cookieKeys.ROLE)) && loggedIn.status === 200 && cookies.get(cookieKeys.APPROVED); - // return roles.includes(cookies.get(cookieKeys.ROLE)); + return { + authenticated: roles.includes(cookies.get(cookieKeys.ROLE)) && loggedIn.status === 200 && cookies.get(cookieKeys.APPROVED), + currentUser, + }; } catch (err) { console.log(err); clearCookies(cookies); @@ -32,16 +36,18 @@ const userIsAuthenticated = async (roles, cookies) => { const ProtectedRoute = ({ Component, redirectPath, roles, cookies }) => { const [isLoading, setIsLoading] = useState(true); const [isAuthenticated, setIsAuthenticated] = useState(false); + const { setCurrentUser } = useAuthContext(); useEffect(() => { const checkAuthentication = async () => { - const authenticated = await userIsAuthenticated(roles, cookies); + const { authenticated, currentUser } = await userIsAuthenticated(roles, cookies); setIsAuthenticated(authenticated); + setCurrentUser(currentUser); setIsLoading(false); }; checkAuthentication(); - }, [roles, cookies]); + }, [roles, cookies, setCurrentUser]); if (isLoading) { return

LOADING...

; } diff --git a/src/utils/auth_config.js b/src/utils/auth_config.js index a40c8f6..6e6f138 100644 --- a/src/utils/auth_config.js +++ b/src/utils/auth_config.js @@ -1,7 +1,7 @@ // Sample roles, feel free to change const AUTH_ROLES = { - ADMIN_ROLE: 'superadmin', - USER_ROLE: 'admin', + ADMIN_ROLE: 'admin', + USER_ROLE: 'student', }; export default { AUTH_ROLES }; diff --git a/src/utils/auth_utils.js b/src/utils/auth_utils.js index 5f9ba3a..68adf11 100644 --- a/src/utils/auth_utils.js +++ b/src/utils/auth_utils.js @@ -92,10 +92,9 @@ const refreshToken = async () => { }); // Sets the appropriate cookies after refreshing access token setCookie(cookieKeys.ACCESS_TOKEN, idToken, cookieConfig); - // const user = await NPOBackend.get(`/users/${auth.currentUser.uid}`); - // setCookie(cookieKeys.ROLE, user.data.user.role, cookieConfig); - setCookie(cookieKeys.ROLE, 'admin', cookieConfig); - return idToken; + const user = await NPOBackend.get(`/users/${auth.currentUser.uid}`); + setCookie(cookieKeys.ROLE, user.data[0].type, cookieConfig); + return {accessToken: idToken, currentUser: user.data[0]}; } return null; };