Files
SGF/resources/js/ModuleNavigation.jsx
T
2026-11-11 09:00:17 +02:00

33 lines
3.3 KiB
React

import React,{useEffect,useRef} from 'react';
const sections = {
human_resources:['human_resources'],
commercial:['services','billing','billing_support'], purchasing:['purchasing'], stock:['stock'],
workshop:['workshop'], finance:['treasury','receivables','costs'], accounting:['accounting'],
};
export function moduleGroups(groups, module) {
if(!sections[module])return [];
const own=groups.filter(g => sections[module].includes(g.id));
if(['commercial','human_resources'].includes(module))return own;
const shared=groups.flatMap(g=>g.items).filter(i=>['clients','services','service_drafts','billing_drafts'].includes(i.id));
return shared.length?[...own,{id:'shared_records',label:'Cadastros e rascunhos do módulo',items:shared}]:own;
}
export function moduleFunctionAllowed(context,groups,module,id){return Boolean(context?.modules?.some(m=>m.id===module)&&(id==='home'||moduleGroups(groups,module).some(g=>g.items.some(i=>i.id===id))));}
export default function ModuleNavigation({groups, context, page, navigate, openPage, user, busy, logout}) {
const active=context?.modules?.find(m=>m.id===context.module_id);
const menu=useRef(null);
useEffect(()=>{const close=e=>{if(!menu.current?.contains(e.target))for(const d of menu.current?.querySelectorAll('details[open]')??[])d.open=false;};window.addEventListener('pointerdown',close);return()=>window.removeEventListener('pointerdown',close);},[]);
const choose=(event,module,id)=>{event.currentTarget.closest('details').open=false;openPage(module,id);};
return <div className="module-navigation">
<div className="module-topbar"><button className="topbar-brand" onClick={()=>navigate('home')}>TEMPO <span>SGF</span></button>
<nav aria-label="Opções gerais"><button aria-current={page==='home'?'page':undefined} onClick={()=>navigate('home')}>Início</button>{groups.find(g=>g.id==='admin')?.items.map(i=><button key={i.id} aria-current={page===i.id?'page':undefined} onClick={()=>navigate(i.id)}>{i.label}</button>)}</nav>
<div className="topbar-account"><strong>{user.name}</strong>{context.single_installation&&<a href="/sgf">Trocar função QA</a>}<button disabled={busy} onClick={logout}>Sair</button></div>
</div>
<nav ref={menu} className="module-menu module-dropdowns" aria-label="Módulos e funções" onKeyDown={event=>{if(event.key==='Escape'){const d=event.target.closest('details');if(d){d.open=false;d.querySelector('summary')?.focus();}}}}>
{context?.modules?.map(module=><details key={module.id} name="sgf-modules" className={active?.id===module.id?'active-module':''}><summary aria-current={active?.id===module.id?'true':undefined}>{module.label}<span aria-hidden="true">▾</span></summary><div aria-label={`Funções de ${module.label}`}><p className="module-dropdown-title">{module.label}</p>{moduleGroups(groups,module.id).map(group=><section key={group.id}><h2>{group.label}</h2>{group.items.map(item=><button key={item.id} disabled={busy} aria-current={active?.id===module.id&&page===item.id?'page':undefined} onClick={event=>choose(event,module.id,item.id)}>{item.label}</button>)}</section>)}</div></details>)}
{!context?.modules?.length&&<span>Sem módulos autorizados neste contexto.</span>}
</nav>
</div>;
}