Ignore:
Timestamp:
12/28/25 00:07:22 (7 months ago)
Author:
Mihail <mihail2.naumov@…>
Branches:
main
Children:
9c87509
Parents:
f7c0b0d
Message:

Added frontend elements

File:
1 edited

Legend:

Unmodified
Added
Removed
  • components/Navbar.tsx

    rf7c0b0d re599341  
    44import Typography from "@mui/material/Typography";
    55import Button from "@mui/material/Button";
    6 import InputBase from "@mui/material/InputBase";
    76import Box from "@mui/material/Box";
    8 import { styled } from "@mui/material/styles";
     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
    925import LogoUrl from '../assets/projectlogo.png';
    10 import {onGetAuthState} from "../pages/+Layout.telefunc";
     26import { onGetAuthState } from "../pages/+Layout.telefunc";
    1127
     28import ComponentDialog from "./ComponentDialog";
    1229
    13 type AuthState = { isLoggedIn: boolean; username: string | null };
     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
    1451
    1552export default function Navbar() {
    1653    const [auth, setAuth] = useState<AuthState | null>(null);
     54    const [openLogoutDialog, setOpenLogoutDialog] = useState(false);
    1755
    18     const handleLogout = async (e: React.MouseEvent) => { // funkcija za logout da go resetira auth state, za da ne go pise username-ot u navbar, plus te vrakja na login nazad
     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) => {
    1977        e.preventDefault();
     78        setOpenLogoutDialog(true);
     79    };
    2080
    21         setAuth({ isLoggedIn: false, username: null });
    22         window.location.href = "/api/auth/signout?callbackUrl=/auth/login";
     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 = "/";
    2392    };
    2493
     
    2695        let active = true;
    2796        onGetAuthState()
    28             .then((data) => active && setAuth({ isLoggedIn: data.isLoggedIn, username: data.username }))
    29             .catch(() => active && setAuth({ isLoggedIn: false, username: null }));
     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 }));
    30103        return () => { active = false; };
    31104    }, []);
    32105
     106    const checkDashboardUrl = auth?.isAdmin ? '/dashboard/admin' : '/dashboard/user';
    33107    const onHoverNav = {
    34108        color: 'inherit',
    35         '&:hover': {
    36             backgroundColor: '#ff8201',
    37             color: 'white',
    38             fontWeight: 'bold',
    39         }
     109        '&:hover': { backgroundColor: '#ff8201', color: 'white', fontWeight: 'bold' }
    40110    };
    41111
    42112    return (
    43         <AppBar position="static" color="default" enableColorOnDark>
    44             <Toolbar>
    45                 <Box sx={{ display: 'flex', alignItems: 'center', mr: 4 }}>
    46                     <Box
    47                         component="img"
    48                         src={LogoUrl}
    49                         alt="PC Forge Logo"
    50                         sx={{ height: 40, mr: 2, cursor: 'pointer' }}
    51                     />
    52                     <Typography
    53                         variant="h6"
    54                         component="a"
    55                         href="/"
    56                         sx={{ textDecoration: "none", color: "inherit", fontWeight: "bold" }}
    57                     >
    58                         PC Forge
    59                     </Typography>
    60                 </Box>
     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>
    61122
    62                 <Box sx={{ display: { xs: "none", md: "flex" }, gap: 2}}>
    63                     <Button color="inherit" href="/forge" sx={onHoverNav}>Forge</Button>
    64                     <Button color="inherit" href="/components" sx={onHoverNav}>Components</Button>
    65                     <Button color="inherit" href="/completed-builds" sx={onHoverNav}>Completed Builds</Button>
    66                 </Box>
     123                    <Box sx={{ display: { xs: "none", md: "flex" }, gap: 2 }}>
     124                        <Button color="inherit" href="/forge" sx={onHoverNav}>Forge</Button>
    67125
    68                 <Box sx={{ flexGrow: 1 }} />
     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>
    69147
    70                 <Box sx={{ display: 'flex', gap: 1 }}>
    71                     {auth?.isLoggedIn ? (
    72                         <>
    73                             <Button sx={onHoverNav} color="inherit" href="/dashboard/user">{auth.username}</Button>
    74                             <Button sx={onHoverNav} color="inherit" onClick={handleLogout}>Logout</Button>
    75                         </>
    76                     ) : (
    77                         <>
    78                             <Button color="inherit" href="/auth/login">Login</Button>
    79                             <Button color="inherit" href="/auth/register">Register</Button>
    80                         </>
    81                     )}
    82                 </Box>
    83             </Toolbar>
    84         </AppBar>
     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        </>
    85186    );
    86187}
Note: See TracChangeset for help on using the changeset viewer.