source: components/Navbar.tsx@ e09fe6f

main
Last change on this file since e09fe6f was e599341, checked in by Mihail <mihail2.naumov@…>, 7 months ago

Added frontend elements

  • Property mode set to 100644
File size: 8.2 KB
Line 
1import React, { useEffect, useState } from "react";
2import AppBar from "@mui/material/AppBar";
3import Toolbar from "@mui/material/Toolbar";
4import Typography from "@mui/material/Typography";
5import Button from "@mui/material/Button";
6import Box from "@mui/material/Box";
7import Menu from "@mui/material/Menu";
8import MenuItem from "@mui/material/MenuItem";
9import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
10import {
11 Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, ListItemText
12} from "@mui/material";
13
14import MemoryIcon from '@mui/icons-material/Memory';
15import DeveloperBoardIcon from '@mui/icons-material/DeveloperBoard';
16import StorageIcon from '@mui/icons-material/Storage';
17import SdStorageIcon from '@mui/icons-material/SdStorage';
18import RouterIcon from '@mui/icons-material/Router';
19import LanIcon from '@mui/icons-material/Lan';
20import SpeakerIcon from '@mui/icons-material/Speaker';
21import AlbumIcon from '@mui/icons-material/Album';
22import SdCardIcon from '@mui/icons-material/SdCard';
23import CableIcon from '@mui/icons-material/Cable';
24
25import LogoUrl from '../assets/projectlogo.png';
26import { onGetAuthState } from "../pages/+Layout.telefunc";
27
28import ComponentDialog from "./ComponentDialog";
29
30type AuthState = { isLoggedIn: boolean; username: string | null; isAdmin?: boolean };
31
32const COMPONENT_CATEGORIES = [
33 { id: 'cpu', label: 'Processors', icon: <MemoryIcon fontSize="small" /> },
34 { id: 'gpu', label: 'Graphics Cards', icon: <DeveloperBoardIcon fontSize="small" /> },
35 { id: 'motherboard', label: 'Motherboards', icon: <DeveloperBoardIcon fontSize="small" /> },
36 { id: 'memory', label: 'Memory (RAM)', icon: <SdStorageIcon fontSize="small" /> },
37 { id: 'storage', label: 'Storage', icon: <StorageIcon fontSize="small" /> },
38 { id: 'case', label: 'Cases', icon: <StorageIcon fontSize="small" /> },
39 { id: 'power_supply', label: 'Power Supplies', icon: <StorageIcon fontSize="small" /> },
40 { id: 'cooler', label: 'Cooling', icon: <StorageIcon fontSize="small" /> },
41
42 // Peripherals / Accessories (Missing ones)
43 { id: 'network_adapter', label: 'Network Adapters (WiFi)', icon: <RouterIcon fontSize="small" /> },
44 { id: 'network_card', label: 'Network Cards (Ethernet)', icon: <LanIcon fontSize="small" /> },
45 { id: 'sound_card', label: 'Sound Cards', icon: <SpeakerIcon fontSize="small" /> },
46 { id: 'optical_drive', label: 'Optical Drives', icon: <AlbumIcon fontSize="small" /> },
47 { id: 'memory_card', label: 'Memory Cards', icon: <SdCardIcon fontSize="small" /> },
48 { id: 'cables', label: 'Cables', icon: <CableIcon fontSize="small" /> },
49];
50
51
52export default function Navbar() {
53 const [auth, setAuth] = useState<AuthState | null>(null);
54 const [openLogoutDialog, setOpenLogoutDialog] = useState(false);
55
56 const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
57 const openMenu = Boolean(anchorEl);
58
59 const [browserOpen, setBrowserOpen] = useState(false);
60 const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
61
62 const handleComponentsClick = (event: React.MouseEvent<HTMLButtonElement>) => {
63 setAnchorEl(event.currentTarget);
64 };
65
66 const handleMenuClose = () => {
67 setAnchorEl(null);
68 };
69
70 const handleCategorySelect = (categoryId: string) => {
71 setSelectedCategory(categoryId);
72 setBrowserOpen(true);
73 handleMenuClose();
74 };
75
76 const handleLogoutClick = (e: React.MouseEvent) => {
77 e.preventDefault();
78 setOpenLogoutDialog(true);
79 };
80
81 const confirmLogout = async () => {
82 setAuth({ isLoggedIn: false, username: null, isAdmin: false });
83 setOpenLogoutDialog(false);
84 const csrfRes = await fetch("/api/auth/csrf");
85 const { csrfToken } = await csrfRes.json();
86 await fetch("/api/auth/signout", {
87 method: "POST",
88 headers: { "Content-Type": "application/x-www-form-urlencoded" },
89 body: new URLSearchParams({ csrfToken: csrfToken, callbackUrl: "/" }),
90 });
91 window.location.href = "/";
92 };
93
94 useEffect(() => {
95 let active = true;
96 onGetAuthState()
97 .then((data) => active && setAuth({
98 isLoggedIn: data.isLoggedIn,
99 username: data.username,
100 isAdmin: data.isAdmin
101 }))
102 .catch(() => active && setAuth({ isLoggedIn: false, username: null, isAdmin: false }));
103 return () => { active = false; };
104 }, []);
105
106 const checkDashboardUrl = auth?.isAdmin ? '/dashboard/admin' : '/dashboard/user';
107 const onHoverNav = {
108 color: 'inherit',
109 '&:hover': { backgroundColor: '#ff8201', color: 'white', fontWeight: 'bold' }
110 };
111
112 return (
113 <>
114 <AppBar position="static" color="default" enableColorOnDark>
115 <Toolbar>
116 <Box sx={{ display: 'flex', alignItems: 'center', mr: 4 }}>
117 <Box component="img" src={LogoUrl} alt="PC Forge Logo" sx={{ height: 40, mr: 2, cursor: 'pointer' }} onClick={() => window.location.href='/'} />
118 <Typography variant="h6" component="a" href="/" sx={{ textDecoration: "none", color: "inherit", fontWeight: "bold" }}>
119 PC Forge
120 </Typography>
121 </Box>
122
123 <Box sx={{ display: { xs: "none", md: "flex" }, gap: 2 }}>
124 <Button color="inherit" href="/forge" sx={onHoverNav}>Forge</Button>
125
126 <Button
127 color="inherit"
128 onClick={handleComponentsClick}
129 endIcon={<KeyboardArrowDownIcon />}
130 sx={onHoverNav}
131 >
132 Components
133 </Button>
134 <Menu
135 anchorEl={anchorEl}
136 open={openMenu}
137 onClose={handleMenuClose}
138 MenuListProps={{ 'aria-labelledby': 'basic-button' }}
139 >
140 {COMPONENT_CATEGORIES.map((cat) => (
141 <MenuItem key={cat.id} onClick={() => handleCategorySelect(cat.id)}>
142 {/*<ListItemIcon>{cat.icon}</ListItemIcon>*/}
143 <ListItemText>{cat.label}</ListItemText>
144 </MenuItem>
145 ))}
146 </Menu>
147
148 <Button color="inherit" href="/completed-builds" sx={onHoverNav}>Completed Builds</Button>
149 </Box>
150
151 <Box sx={{ flexGrow: 1 }} />
152
153 <Box sx={{ display: 'flex', gap: 1 }}>
154 {auth?.isLoggedIn ? (
155 <>
156 <Button sx={onHoverNav} color="inherit" href={checkDashboardUrl}>{auth.username}</Button>
157 <Button sx={onHoverNav} color="inherit" onClick={handleLogoutClick}>Logout</Button>
158 </>
159 ) : (
160 <>
161 <Button color="inherit" href="/auth/login">Login</Button>
162 <Button color="inherit" href="/auth/register">Register</Button>
163 </>
164 )}
165 </Box>
166 </Toolbar>
167 </AppBar>
168
169 <Dialog open={openLogoutDialog} onClose={() => setOpenLogoutDialog(false)}>
170 <DialogTitle>Confirm Logout</DialogTitle>
171 <DialogContent>
172 <DialogContentText>Are you sure you want to leave the Forge?</DialogContentText>
173 </DialogContent>
174 <DialogActions>
175 <Button onClick={() => setOpenLogoutDialog(false)}>Cancel</Button>
176 <Button onClick={confirmLogout} color="error" variant="contained" autoFocus>Logout</Button>
177 </DialogActions>
178 </Dialog>
179
180 <ComponentDialog
181 open={browserOpen}
182 category={selectedCategory}
183 onClose={() => setBrowserOpen(false)}
184 />
185 </>
186 );
187}
Note: See TracBrowser for help on using the repository browser.