mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
init Admin frontend
This commit is contained in:
parent
112062c0b2
commit
16ec234ed8
5 changed files with 149 additions and 12 deletions
|
|
@ -29,6 +29,7 @@ import OAuthCallback from './pages/AuthManager/callback/AuthCallback';
|
|||
const App: React.FC = () => {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn());
|
||||
const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher());
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null);
|
||||
const location = useLocation();
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ const App: React.FC = () => {
|
|||
const checkLoginStatus = () => {
|
||||
setIsAuthenticated(ApiService.isLoggedIn());
|
||||
setIsTeacherAuthenticated(ApiService.isLoggedInTeacher());
|
||||
//setIsAdmin(ApiService.isAdmin());
|
||||
};
|
||||
|
||||
const fetchAuthenticatedRooms = async () => {
|
||||
|
|
@ -56,7 +58,7 @@ const App: React.FC = () => {
|
|||
|
||||
return (
|
||||
<div className="content">
|
||||
<Header isLoggedIn={isAuthenticated} handleLogout={handleLogout} />
|
||||
<Header isLoggedIn={isAuthenticated} isAdmin={true} handleLogout={handleLogout} />
|
||||
<div className="app">
|
||||
<main>
|
||||
<Routes>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import AdminDrawer from '../../../components/AdminDrawer/AdminDrawer';
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
describe('AdminDrawer Component', () => {
|
||||
test('renders the Admin button', () => {
|
||||
render(<AdminDrawer />);
|
||||
|
||||
// Check if the "Admin" button is in the document
|
||||
const button = screen.getByRole('button', { name: /admin/i });
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('opens the drawer when the button is clicked', () => {
|
||||
render(<AdminDrawer />);
|
||||
|
||||
// Click the "Admin" button
|
||||
const button = screen.getByRole('button', { name: /admin/i });
|
||||
fireEvent.click(button);
|
||||
|
||||
// Check if the drawer is open (it should be a right-side drawer, so check for list items)
|
||||
const statsItem = screen.getByText(/Stats/i);
|
||||
expect(statsItem).toBeInTheDocument();
|
||||
});
|
||||
//TODO modify this test as no redirect as of yet
|
||||
/*
|
||||
test('closes the drawer when an item is clicked', () => {
|
||||
render(<AdminDrawer />);
|
||||
|
||||
// Open the drawer by clicking the "Admin" button
|
||||
const button = screen.getByRole('button', { name: /admin/i });
|
||||
fireEvent.click(button);
|
||||
|
||||
// Click on a menu item (Stats, Images, or Users)
|
||||
const statsItem = screen.getByText(/Stats/i);
|
||||
expect(statsItem).toBeInTheDocument();
|
||||
fireEvent.click(statsItem);
|
||||
|
||||
// Ensure that the drawer is closed after clicking an item
|
||||
const statsItemAgain = screen.queryByText(/Stats/i);
|
||||
expect(statsItemAgain).not.toBeInTheDocument();
|
||||
});
|
||||
*/
|
||||
test('menu items render correctly', () => {
|
||||
render(<AdminDrawer />);
|
||||
|
||||
// Open the drawer
|
||||
const button = screen.getByRole('button', { name: /admin/i });
|
||||
fireEvent.click(button);
|
||||
|
||||
// Check if all the menu items are rendered
|
||||
expect(screen.getByText(/Stats/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Images/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Users/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
64
client/src/components/AdminDrawer/AdminDrawer.tsx
Normal file
64
client/src/components/AdminDrawer/AdminDrawer.tsx
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Drawer from '@mui/material/Drawer';
|
||||
import Button from '@mui/material/Button';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import BarChartIcon from '@mui/icons-material/BarChart';
|
||||
import ImageIcon from '@mui/icons-material/Image';
|
||||
import PeopleIcon from '@mui/icons-material/People';
|
||||
|
||||
const styles = {
|
||||
drawerBg: 'rgba(82, 113, 255, 0.85)',
|
||||
drawerTxtColor: 'white',
|
||||
btnBg: 'rgba(82, 113, 255, 1)',
|
||||
btnHover: 'rgba(65, 105, 225, 0.7)',
|
||||
height: '100%'
|
||||
};
|
||||
|
||||
export default function AdminDrawer() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const toggleDrawer = (isOpen: boolean) => () => {
|
||||
setOpen(isOpen);
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{ text: 'Stats', icon: <BarChartIcon /> },
|
||||
{ text: 'Images', icon: <ImageIcon /> },
|
||||
{ text: 'Users', icon: <PeopleIcon /> },
|
||||
];
|
||||
|
||||
const list = (
|
||||
<Box sx={{ width: 250, backgroundColor: styles.drawerBg, height: styles.height, color: styles.drawerTxtColor }} role="presentation" onClick={toggleDrawer(false)}>
|
||||
<List>
|
||||
{menuItems.map(({ text, icon }) => (
|
||||
<ListItem key={text} disablePadding>
|
||||
<ListItemButton>
|
||||
<ListItemIcon sx={{ color: styles.drawerTxtColor }}>{icon}</ListItemIcon>
|
||||
<ListItemText primary={text} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
sx={{ backgroundColor: styles.btnBg, color: 'white', '&:hover': { backgroundColor: styles.btnHover } }}
|
||||
onClick={toggleDrawer(true)}
|
||||
>
|
||||
Admin
|
||||
</Button>
|
||||
<Drawer anchor="right" open={open} onClose={toggleDrawer(false)}>
|
||||
{list}
|
||||
</Drawer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,13 +2,15 @@ import { Link, useNavigate } from 'react-router-dom';
|
|||
import * as React from 'react';
|
||||
import './header.css';
|
||||
import { Button } from '@mui/material';
|
||||
import AdminDrawer from '../AdminDrawer/AdminDrawer';
|
||||
|
||||
interface HeaderProps {
|
||||
isLoggedIn: boolean;
|
||||
isAdmin: boolean;
|
||||
handleLogout: () => void;
|
||||
}
|
||||
|
||||
const Header: React.FC<HeaderProps> = ({ isLoggedIn, handleLogout }) => {
|
||||
const Header: React.FC<HeaderProps> = ({ isLoggedIn, isAdmin, handleLogout }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
|
|
@ -21,18 +23,24 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, handleLogout }) => {
|
|||
/>
|
||||
|
||||
{isLoggedIn && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
handleLogout();
|
||||
navigate('/');
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
<div className="button-group">
|
||||
|
||||
{ isAdmin && <AdminDrawer /> }
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
handleLogout();
|
||||
navigate('/');
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{!isLoggedIn && (
|
||||
<div className="auth-selection-btn">
|
||||
<Link to="/login">
|
||||
|
|
|
|||
|
|
@ -11,4 +11,10 @@
|
|||
|
||||
.header img {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
Loading…
Reference in a new issue