streamflow/frontend/src/components/Sidebar.jsx
2025-12-17 00:42:43 +00:00

165 lines
4.6 KiB
JavaScript

import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import {
Drawer,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Box,
Typography,
Avatar
} from '@mui/material';
import {
LiveTv,
Movie,
Theaters,
Favorite,
Settings,
Radio as RadioIcon,
BarChart,
Security
} from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import { useAuthStore } from '../store/authStore';
import Logo from './Logo';
const drawerWidth = 200;
function Sidebar({ open, onClose }) {
const { t } = useTranslation();
const navigate = useNavigate();
const location = useLocation();
const { user } = useAuthStore();
const menuItems = [
{ text: 'live_tv', icon: <LiveTv fontSize="small" />, path: '/live-tv' },
{ text: 'radio', icon: <RadioIcon fontSize="small" />, path: '/radio' },
{ text: 'favorite_tv', icon: <Favorite fontSize="small" />, path: '/favorites/tv' },
{ text: 'favorite_radio', icon: <Favorite fontSize="small" />, path: '/favorites/radio' },
...(user?.role === 'admin' ? [
{ text: 'Analytics', icon: <BarChart fontSize="small" />, path: '/stats' },
{ text: 'security.title', icon: <Security fontSize="small" />, path: '/security' }
] : []),
{ text: 'settings.title', icon: <Settings fontSize="small" />, path: '/settings' }
];
const handleNavigate = (path) => {
navigate(path);
onClose();
};
const drawerContent = (
<>
<Box sx={{ p: 2, textAlign: 'center' }}>
<Logo size={36} />
<Typography variant="h6" fontSize="0.95rem" fontWeight="bold" sx={{ mt: 0.5 }}>
{t('app_name')}
</Typography>
</Box>
<Box sx={{ px: 1.5, mb: 1.5 }}>
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
p: 1,
borderRadius: 1.5,
bgcolor: 'action.hover'
}}
>
<Avatar sx={{ width: 28, height: 28, bgcolor: 'primary.main', fontSize: '0.875rem' }}>
{user?.username?.[0]?.toUpperCase()}
</Avatar>
<Typography variant="body2" fontSize="0.8rem" fontWeight="600" noWrap>
{user?.username}
</Typography>
</Box>
</Box>
<List sx={{ px: 1.5 }}>
{menuItems.map((item) => {
const isActive = location.pathname === item.path ||
(item.path === '/live-tv' && location.pathname === '/') ||
(item.path === '/favorites/tv' && location.pathname === '/favorites');
return (
<ListItem key={item.text} disablePadding sx={{ mb: 0.5 }}>
<ListItemButton
selected={isActive}
onClick={() => handleNavigate(item.path)}
sx={{
borderRadius: 1.5,
minHeight: 36,
py: 0.75,
'&.Mui-selected': {
bgcolor: 'primary.main',
color: 'white',
'&:hover': {
bgcolor: 'primary.dark'
},
'& .MuiListItemIcon-root': {
color: 'white'
}
}
}}
>
<ListItemIcon sx={{ minWidth: 32, color: isActive ? 'white' : 'inherit' }}>
{item.icon}
</ListItemIcon>
<ListItemText
primary={t(item.text)}
primaryTypographyProps={{ fontSize: '0.8125rem' }}
/>
</ListItemButton>
</ListItem>
);
})}
</List>
</>
);
return (
<>
{/* Mobile drawer - temporary */}
<Drawer
variant="temporary"
open={open}
onClose={onClose}
sx={{
display: { xs: 'block', md: 'none' },
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
borderRight: 'none'
}
}}
>
{drawerContent}
</Drawer>
{/* Desktop drawer - permanent, always visible */}
<Drawer
variant="permanent"
sx={{
display: { xs: 'none', md: 'block' },
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
borderRight: 'none',
position: 'relative'
}
}}
>
{drawerContent}
</Drawer>
</>
);
}
export default Sidebar;