testes/src_2/features/layout/components/Sidebar/Sidebar.jsx

212 lines
5.7 KiB
JavaScript

import React, { useState, useMemo } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
import {
ChevronLeft,
ChevronRight,
Search,
ChevronDown,
ShieldAlert,
Building2,
Award,
GitBranch,
Lock,
LayoutDashboard,
Truck,
Users,
Wrench,
BarChart3,
Map,
Link as LinkIcon,
Settings,
Folder
} from 'lucide-react';
import { cn } from '@/lib/utils';
import './Sidebar.css';
const MENU_ITEMS = [
{
id: 'dashboard',
label: 'Dashboard',
icon: LayoutDashboard,
path: '/plataforma/dashboard'
},
{
id: 'veiculos',
label: 'Veículos',
icon: Truck,
children: [
{ id: 'v-lista', label: 'Veículos', path: '/plataforma/veiculos', icon: Truck },
{ id: 'v-combustivel', label: 'Controle de Combustível', path: '/plataforma/combustivel', icon: Folder },
{ id: 'v-rastreadores', label: 'Rastreadores', path: '/plataforma/rastreadores', icon: Folder }
]
},
{
id: 'motoristas',
label: 'Motoristas',
icon: Users,
children: [
{ id: 'm-lista', label: 'Cadastro', path: '/plataforma/motoristas', icon: Users },
{ id: 'm-escala', label: 'Escalas', path: '/plataforma/escalas', icon: Folder }
]
},
{
id: 'manutencao',
label: 'Manutenção',
icon: Wrench,
disabled: true,
disabledReason: 'Funcionalidade bloqueada temporariamente'
},
{
id: 'relatorios',
label: 'Relatórios',
icon: BarChart3,
path: '/plataforma/relatorios'
},
{
id: 'mapa',
label: 'Mapa',
icon: Map,
path: '/plataforma/mapa'
},
{
id: 'integracoes',
label: 'Integrações',
icon: LinkIcon,
path: '/plataforma/integracoes'
},
{
id: 'configuracoes',
label: 'Configurações',
icon: Settings,
path: '/plataforma/configuracoes'
}
];
export const Sidebar = ({ isCollapsed: initialCollapsed = false }) => {
const [isCollapsed, setIsCollapsed] = useState(initialCollapsed);
const [searchTerm, setSearchTerm] = useState('');
const [expandedItems, setExpandedItems] = useState({});
const location = useLocation();
const toggleSidebar = () => setIsCollapsed(!isCollapsed);
const toggleExpand = (id) => {
setExpandedItems(prev => ({
...prev,
[id]: !prev[id]
}));
};
const filteredItems = useMemo(() => {
if (!searchTerm) return MENU_ITEMS;
return MENU_ITEMS.filter(item => {
const matchParent = item.label.toLowerCase().includes(searchTerm.toLowerCase());
const matchChildren = item.children?.some(child =>
child.label.toLowerCase().includes(searchTerm.toLowerCase())
);
return matchParent || matchChildren;
});
}, [searchTerm]);
const MenuItem = ({ item, isSub = false }) => {
const Icon = item.icon;
const hasChildren = item.children && item.children.length > 0;
const isExpanded = expandedItems[item.id];
const isActive = location.pathname === item.path || (hasChildren && item.children.some(c => location.pathname === c.path));
const isLocked = item.disabled;
const content = (
<div
className={cn(
isSub ? "sb-sublink" : "sb-link",
isActive && !hasChildren && "active",
isLocked && "sb-locked"
)}
onClick={() => {
if (isLocked) return;
if (hasChildren) toggleExpand(item.id);
}}
title={isLocked ? item.disabledReason : (isCollapsed ? item.label : '')}
>
<Icon size={isSub ? 16 : 20} className="sb-icon" />
{(!isCollapsed || isSub) && <span className="sb-label">{item.label}</span>}
{hasChildren && !isCollapsed && (
<ChevronDown
size={14}
className={cn("sb-chevron", isExpanded && "expanded")}
/>
)}
{isLocked && !isCollapsed && (
<Lock size={12} className="sb-lock-icon" />
)}
</div>
);
return (
<div className="sb-item">
{item.path && !hasChildren && !isLocked ? (
<Link to={item.path} style={{ textDecoration: 'none' }}>
{content}
</Link>
) : content}
{hasChildren && isExpanded && !isCollapsed && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="sb-submenu"
>
{item.children.map(child => (
<MenuItem key={child.id} item={child} isSub />
))}
</motion.div>
)}
</div>
);
};
return (
<aside className={cn("sb-container", isCollapsed && "collapsed")}>
<div className="sb-toggle-container">
<button className="sb-toggle-btn" onClick={toggleSidebar}>
{isCollapsed ? <ChevronRight size={18} /> : <ChevronLeft size={18} />}
</button>
</div>
<div className="sb-search-wrapper">
<input
type="text"
className="sb-search-input"
placeholder="Buscar..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<nav className="sb-menu-content">
{filteredItems.map(item => (
<MenuItem key={item.id} item={item} />
))}
</nav>
<footer className="sb-footer">
<div className="sb-brand">
<div className="sb-brand-logo">
<ShieldAlert size={22} fill="currentColor" />
</div>
<div className="sb-brand-info">
<span className="sb-brand-name">Grupo PRA</span>
<span className="sb-app-name">PraFrota</span>
</div>
</div>
</footer>
</aside>
);
};