Auto-deploy: 2026-01-13 12:49:39 | 1 arquivo(s) alterado(s)
This commit is contained in:
parent
9f125250a6
commit
5813271e9f
|
|
@ -41,7 +41,7 @@ const MENU_ITEMS = [
|
|||
children: [
|
||||
{ id: 'c-veiculos', label: 'Veículos', path: '/plataforma/prafrot/veiculos', icon: Car },
|
||||
{ id: 'c-dispatcher', label: 'Dispatcher', path: '/plataforma/prafrot/dispatcher', icon: ClipboardList },
|
||||
{ id: 'c-motoristas', label: 'Motoristas', path: '/plataforma/prafrot/motoristas', icon: Users, disabled: true, disabledReason: 'Funcionalidade em manutenção' },
|
||||
// { id: 'c-motoristas', label: 'Motoristas', path: '/plataforma/prafrot/motoristas', icon: Users, disabled: true, disabledReason: 'Funcionalidade em manutenção' },
|
||||
{ id: 'c-oficinas', label: 'Oficinas', path: '/plataforma/prafrot/oficinas', icon: Store }
|
||||
]
|
||||
},
|
||||
|
|
@ -57,18 +57,97 @@ const MENU_ITEMS = [
|
|||
}
|
||||
];
|
||||
|
||||
// Optimized MenuItem component outside main render loop
|
||||
const MenuItem = React.memo(({ item, isSub = false, isCollapsed, expandedItems, toggleExpand, pathname, searchTerm }) => {
|
||||
const Icon = item.icon;
|
||||
const hasChildren = item.children && item.children.length > 0;
|
||||
const isExpanded = expandedItems[item.id];
|
||||
const isActive = pathname.startsWith(item.path) || (hasChildren && item.children.some(c => pathname.startsWith(c.path)));
|
||||
const isLocked = item.disabled;
|
||||
|
||||
// Filter sub-items if searching
|
||||
const subItems = item.children?.filter(child =>
|
||||
!searchTerm || child.label.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
const content = (
|
||||
<div
|
||||
className={cn(
|
||||
isSub ? "pfs-sublink" : "pfs-link",
|
||||
isActive && !hasChildren && "active",
|
||||
isLocked && "pfs-locked"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (isLocked) return;
|
||||
if (hasChildren) toggleExpand(item.id);
|
||||
}}
|
||||
title={isLocked ? item.disabledReason : (isCollapsed ? item.label : '')}
|
||||
>
|
||||
<Icon size={isSub ? 16 : 20} className="pfs-icon" />
|
||||
{(!isCollapsed || isSub) && <span className="pfs-label">{item.label}</span>}
|
||||
|
||||
{hasChildren && !isCollapsed && (
|
||||
<ChevronDown
|
||||
size={14}
|
||||
className={cn("pfs-chevron", isExpanded && "expanded")}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isLocked && !isCollapsed && (
|
||||
<Lock size={12} className="pfs-lock-icon" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="pfs-item-wrapper">
|
||||
{item.path && !hasChildren && !isLocked ? (
|
||||
<Link to={item.path} style={{ textDecoration: 'none' }}>
|
||||
{content}
|
||||
</Link>
|
||||
) : content}
|
||||
|
||||
<AnimatePresence>
|
||||
{hasChildren && isExpanded && !isCollapsed && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="pfs-submenu"
|
||||
>
|
||||
{subItems?.map(child => (
|
||||
<MenuItem
|
||||
key={child.id}
|
||||
item={child}
|
||||
isSub
|
||||
isCollapsed={isCollapsed}
|
||||
expandedItems={expandedItems}
|
||||
toggleExpand={toggleExpand}
|
||||
pathname={pathname}
|
||||
searchTerm={searchTerm}
|
||||
/>
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
MenuItem.displayName = 'MenuItem';
|
||||
|
||||
export const PrafrotSidebar = ({ isCollapsed, onToggle }) => {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [expandedItems, setExpandedItems] = useState({ cadastros: true, gerencia: true });
|
||||
const location = useLocation();
|
||||
const { user, logout } = useAuthContext();
|
||||
|
||||
const toggleExpand = (id) => {
|
||||
const toggleExpand = React.useCallback((id) => {
|
||||
setExpandedItems(prev => ({
|
||||
...prev,
|
||||
[id]: !prev[id]
|
||||
}));
|
||||
};
|
||||
}, []);
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
if (!searchTerm) return MENU_ITEMS;
|
||||
|
|
@ -87,71 +166,6 @@ export const PrafrotSidebar = ({ isCollapsed, onToggle }) => {
|
|||
window.location.href = '/plataforma/prafrot/login';
|
||||
};
|
||||
|
||||
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.startsWith(item.path) || (hasChildren && item.children.some(c => location.pathname.startsWith(c.path)));
|
||||
const isLocked = item.disabled;
|
||||
|
||||
// Filter sub-items if searching
|
||||
const subItems = item.children?.filter(child =>
|
||||
!searchTerm || child.label.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
const content = (
|
||||
<div
|
||||
className={cn(
|
||||
isSub ? "pfs-sublink" : "pfs-link",
|
||||
isActive && !hasChildren && "active",
|
||||
isLocked && "pfs-locked"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (isLocked) return;
|
||||
if (hasChildren) toggleExpand(item.id);
|
||||
}}
|
||||
title={isLocked ? item.disabledReason : (isCollapsed ? item.label : '')}
|
||||
>
|
||||
<Icon size={isSub ? 16 : 20} className="pfs-icon" />
|
||||
{(!isCollapsed || isSub) && <span className="pfs-label">{item.label}</span>}
|
||||
|
||||
{hasChildren && !isCollapsed && (
|
||||
<ChevronDown
|
||||
size={14}
|
||||
className={cn("pfs-chevron", isExpanded && "expanded")}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isLocked && !isCollapsed && (
|
||||
<Lock size={12} className="pfs-lock-icon" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="pfs-item-wrapper">
|
||||
{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="pfs-submenu"
|
||||
>
|
||||
{subItems.map(child => (
|
||||
<MenuItem key={child.id} item={child} isSub />
|
||||
))}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className={cn("pfs-container", isCollapsed && "collapsed")}>
|
||||
<div className="pfs-toggle-container">
|
||||
|
|
@ -175,7 +189,15 @@ export const PrafrotSidebar = ({ isCollapsed, onToggle }) => {
|
|||
|
||||
<nav className="pfs-nav-content custom-scrollbar">
|
||||
{filteredItems.map(item => (
|
||||
<MenuItem key={item.id} item={item} />
|
||||
<MenuItem
|
||||
key={item.id}
|
||||
item={item}
|
||||
isCollapsed={isCollapsed}
|
||||
expandedItems={expandedItems}
|
||||
toggleExpand={toggleExpand}
|
||||
pathname={location.pathname}
|
||||
searchTerm={searchTerm}
|
||||
/>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue