Files
hMarket/frontend/src/components/Layout/Navbar.tsx

282 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import {
AppBar,
Toolbar,
Typography,
Button,
IconButton,
Menu,
MenuItem,
Avatar,
Badge,
Box,
useTheme,
useMediaQuery,
Drawer,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Divider,
} from '@mui/material';
import {
Menu as MenuIcon,
Notifications as NotificationsIcon,
AccountCircle,
Dashboard,
List as ListIcon,
Inventory,
Settings,
AdminPanelSettings,
Logout,
ShoppingCart,
} from '@mui/icons-material';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import { useQuery } from '@tanstack/react-query';
import { notificationsAPI } from '../../services/api';
const Navbar: React.FC = () => {
const navigate = useNavigate();
const location = useLocation();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const { user, logout, isAuthenticated } = useAuth();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [mobileOpen, setMobileOpen] = useState(false);
// Get unread notifications count
const { data: unreadCount } = useQuery({
queryKey: ['notifications', 'unread-count'],
queryFn: () => notificationsAPI.getUnreadCount(),
enabled: isAuthenticated,
refetchInterval: 30000, // Refetch every 30 seconds
});
const handleProfileMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
const handleLogout = () => {
logout();
handleMenuClose();
navigate('/login');
};
const menuItems = [
{ text: 'Anasayfa', icon: <Dashboard />, path: '/dashboard' },
{ text: 'Listeler', icon: <ListIcon />, path: '/lists' },
{ text: 'Ürünler', icon: <Inventory />, path: '/products' },
];
if (user?.role === 'ADMIN') {
menuItems.push({ text: 'Yönetim', icon: <AdminPanelSettings />, path: '/admin' });
}
const drawer = (
<Box sx={{ width: 250 }}>
<Box sx={{ p: 2, display: 'flex', alignItems: 'center' }}>
<ShoppingCart sx={{ mr: 1, color: 'primary.main' }} />
<Typography variant="h6" color="primary.main" fontWeight="bold">
hMarket
</Typography>
</Box>
<Divider />
<List>
{menuItems.map((item) => (
<ListItem key={item.text} disablePadding>
<ListItemButton
onClick={() => {
navigate(item.path);
setMobileOpen(false);
}}
selected={location.pathname === item.path}
>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<List>
<ListItem disablePadding>
<ListItemButton
onClick={() => {
navigate('/profile');
setMobileOpen(false);
}}
selected={location.pathname === '/profile'}
>
<ListItemIcon><Settings /></ListItemIcon>
<ListItemText primary="Profil" />
</ListItemButton>
</ListItem>
<ListItem disablePadding>
<ListItemButton onClick={handleLogout}>
<ListItemIcon><Logout /></ListItemIcon>
<ListItemText primary=ıkış" />
</ListItemButton>
</ListItem>
</List>
</Box>
);
if (!isAuthenticated) {
return (
<AppBar position="sticky" color="primary">
<Toolbar>
<Box sx={{ display: 'flex', alignItems: 'center', flexGrow: 1 }}>
<ShoppingCart sx={{ mr: 1 }} />
<Typography variant="h6" component="div" fontWeight="bold">
hMarket
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Button
color="inherit"
onClick={() => navigate('/login')}
variant={location.pathname === '/login' ? 'outlined' : 'text'}
>
Giriş
</Button>
<Button
color="inherit"
onClick={() => navigate('/register')}
variant={location.pathname === '/register' ? 'outlined' : 'text'}
>
Kayıt
</Button>
</Box>
</Toolbar>
</AppBar>
);
}
return (
<>
<AppBar position="sticky" color="primary">
<Toolbar>
{isMobile && (
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
)}
<Box sx={{ display: 'flex', alignItems: 'center', flexGrow: 1 }}>
<ShoppingCart sx={{ mr: 1 }} />
<Typography
variant="h6"
component="div"
fontWeight="bold"
sx={{ cursor: 'pointer' }}
onClick={() => navigate('/dashboard')}
>
hMarket
</Typography>
</Box>
{!isMobile && (
<Box sx={{ display: 'flex', gap: 1, mr: 2 }}>
{menuItems.map((item) => (
<Button
key={item.text}
color="inherit"
onClick={() => navigate(item.path)}
variant={location.pathname === item.path ? 'outlined' : 'text'}
startIcon={item.icon}
>
{item.text}
</Button>
))}
</Box>
)}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<IconButton color="inherit" onClick={() => navigate('/notifications')}>
<Badge badgeContent={unreadCount?.data?.data?.count || 0} color="error">
<NotificationsIcon />
</Badge>
</IconButton>
<IconButton
size="large"
edge="end"
aria-label="account of current user"
aria-controls="primary-search-account-menu"
aria-haspopup="true"
onClick={handleProfileMenuOpen}
color="inherit"
>
{user?.avatar ? (
<Avatar src={user.avatar} sx={{ width: 32, height: 32 }} />
) : (
<AccountCircle />
)}
</IconButton>
</Box>
</Toolbar>
</AppBar>
{/* Mobile drawer */}
<Drawer
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: 250 },
}}
>
{drawer}
</Drawer>
{/* Profile menu */}
<Menu
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
id="primary-search-account-menu"
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
>
<MenuItem onClick={() => { navigate('/profile'); handleMenuClose(); }}>
<Settings sx={{ mr: 1 }} />
Profil
</MenuItem>
<MenuItem onClick={handleLogout}>
<Logout sx={{ mr: 1 }} />
Çıkış
</MenuItem>
</Menu>
</>
);
};
export default Navbar;