/* JRN — App shell, navegação, controle de acesso e Tweaks */ const { useState: uS, useEffect } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "companyInteraction": "click", "sidebar": "navy", "showBrandBar": true }/*EDITMODE-END*/; /* Itens de navegação administrativos e a função que cada um exige */ const ADMIN_NAV = [ { id: 'admin-dashboards', label: 'Dashboards', icon: 'chart', fn: 'dash_cadastro' }, { id: 'admin-users', label: 'Usuários', icon: 'users', fn: 'user_edicao' }, { id: 'admin-companies', label: 'Empresas', icon: 'building', fn: null }, { id: 'admin-audit', label: 'Auditoria', icon: 'history', fn: 'auditoria' }, ]; function canSee(user, fn) { if (!user) return false; if (user.perfil === 'admin') return true; if (!fn) return false; const fns = user.funcoes || []; return fns.includes('*') || fns.includes(fn); } function Sidebar({ user, view, setView, tweaks, collapsed, onToggle, onLogout }) { const dark = tweaks.sidebar === 'navy'; const [userOpen, setUserOpen] = useState(false); const adminItems = ADMIN_NAV.filter(i => canSee(user, i.fn)); const C = { bg: dark ? 'linear-gradient(180deg,#15233f,#0d1730)' : '#fff', fg: dark ? '#fff' : 'var(--ink)', muted: dark ? '#8ea0c4' : 'var(--muted)', line: dark ? 'rgba(255,255,255,.1)' : 'var(--line)', activeBg: dark ? 'rgba(255,255,255,.12)' : 'var(--navy-100)', activeFg: dark ? '#fff' : 'var(--navy-800)', hover: dark ? 'rgba(255,255,255,.06)' : 'var(--navy-50)', }; const NavItem = ({ id, label, icon }) => { const I = Icons[icon]; const active = view === id || (id === 'portal' && (view === 'portal' || view === 'dashboard')); return ( setView(id)} title={collapsed ? label : undefined} style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', padding: collapsed ? '11px 0' : '11px 13px', justifyContent: collapsed ? 'center' : 'flex-start', borderRadius: 9, border: 'none', cursor: 'pointer', fontSize: 14, fontWeight: 600, background: active ? C.activeBg : 'transparent', color: active ? C.activeFg : C.muted, transition: 'background .13s', fontFamily: 'var(--font-ui)', whiteSpace: 'nowrap', overflow: 'hidden', }} onMouseEnter={e => { if (!active) e.currentTarget.style.background = C.hover; }} onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}> {!collapsed && label} ); }; return (