import { useEffect, useMemo, useState } from 'react' import { ROLE_LABELS, ROLE_NAV_ITEMS } from '../config/permissions.js' import { authRepository } from '../repositories/authRepository.js' import { profileRepository } from '../repositories/profileRepository.js' import { BrandLogo } from './Brand.jsx' // Todos os itens de navegação com seus ícones e metadados const ALL_NAV_ITEMS = [ { href: '/inicio', label: 'Painel', icon: 'pulse', activePaths: ['/inicio', '/home', '/dashboard'] }, { href: '/agenda', label: 'Agenda', icon: 'calendar' }, { href: '/pacientes', label: 'Pacientes', icon: 'users', exact: true }, { href: '/prontuario', label: 'Prontuário', icon: 'file' }, { href: '/laudos', label: 'Relatórios', icon: 'clipboard' }, { href: '/comunicacao', label: 'Comunicação', icon: 'message', activePaths: ['/comunicacao', '/mensagens'], }, { href: '/relatorios', label: 'Analytics', icon: 'chart' }, { href: '/usuarios', label: 'Usuários', icon: 'shield' }, { href: '/configuracoes', label: 'Configurações', icon: 'settings', activePaths: ['/configuracoes', '/config'] }, ] const titles = { '/inicio': 'Painel', '/home': 'Painel', '/dashboard': 'Painel', '/agenda': 'Agenda', '/consultas': 'Consultas', '/laudos': 'Relatórios', '/pacientes': 'Pacientes', '/prontuario': 'Prontuário', '/comunicacao': 'Comunicação', '/mensagens': 'Comunicação', '/relatorios': 'Analytics', '/perfil': 'Perfil', '/configuracoes': 'Configurações', '/config': 'Configurações', '/usuarios': 'Usuários', } export function AppShell({ children, currentPath, navigate, role, routeTitle }) { const [menuOpen, setMenuOpen] = useState(false) const [profileMenuOpen, setProfileMenuOpen] = useState(false) const [notificationsOpen, setNotificationsOpen] = useState(false) const [viewerProfile, setViewerProfile] = useState({ name: 'Usuário', role: 'Usuário do Sistema' }) const pageTitle = useMemo(() => { if (currentPath.startsWith('/pacientes/') && routeTitle) { return routeTitle } return routeTitle || titles[currentPath] || 'MediConnect' }, [currentPath, routeTitle]) // Filtra os itens de navegação com base no role do usuário const navItems = useMemo(() => { if (!role) return [] const allowedPaths = ROLE_NAV_ITEMS[role]?.map((item) => item.path) ?? [] return ALL_NAV_ITEMS.filter((item) => allowedPaths.some( (allowed) => item.href === allowed || item.activePaths?.includes(allowed), ), ) }, [role]) const canOpenSettings = useMemo( () => (ROLE_NAV_ITEMS[role] ?? []).some( (item) => item.path === '/configuracoes' || item.path === '/config', ), [role], ) const mockNotifications = useMemo( () => [ { id: 'mock-1', title: 'Retorno agendado', detail: 'Paciente Ana Souza às 14:30', time: 'Agora' }, { id: 'mock-2', title: 'Laudo pendente', detail: 'Hemograma aguardando revisão', time: '12 min' }, { id: 'mock-3', title: 'Mensagem recebida', detail: 'Resposta via WhatsApp registrada', time: '35 min' }, ], [], ) useEffect(() => { let active = true profileRepository .getCurrentUserProfile() .then((profile) => { if (!active || !profile) return setViewerProfile({ name: profile.name || 'Usuário', role: ROLE_LABELS[role] || profile.role || 'Usuário do Sistema', }) }) .catch(() => { // Fallback: usa o label do role diretamente if (active && role) { setViewerProfile((prev) => ({ ...prev, role: ROLE_LABELS[role] || 'Usuário do Sistema', })) } }) return () => { active = false } }, [role]) useEffect(() => { if (!profileMenuOpen && !notificationsOpen) return undefined function closeOnEscape(event) { if (event.key === 'Escape') { setProfileMenuOpen(false) setNotificationsOpen(false) } } window.addEventListener('keydown', closeOnEscape) return () => window.removeEventListener('keydown', closeOnEscape) }, [notificationsOpen, profileMenuOpen]) function goTo(path) { setMenuOpen(false) setProfileMenuOpen(false) setNotificationsOpen(false) navigate(path) } async function handleLogout() { setProfileMenuOpen(false) await authRepository.logout() navigate('/login', { replace: true }) } return (
Pular para conteúdo {menuOpen ? (
{notificationsOpen ? (

Notificações

Mock
{mockNotifications.map((notification) => ( ))}
) : null}
{pageTitle}
{children}
) } function NavItem({ active, item, onNavigate }) { return ( { event.preventDefault() onNavigate(item.href) }} > {item.label} ) } function isActive(pathname, item) { if (item.activePaths?.some((path) => pathname === path || pathname.startsWith(`${path}/`))) { return true } if (item.activePrefixes?.some((path) => pathname.startsWith(path))) { return true } if (item.exact) { return pathname === item.href } return pathname === item.href || pathname.startsWith(`${item.href}/`) } function AppIcon({ className = 'size-5', name }) { const common = { className, fill: 'none', stroke: 'currentColor', strokeLinecap: 'round', strokeLinejoin: 'round', strokeWidth: 1.8, viewBox: '0 0 24 24', } if (name === 'calendar') { return ( ) } if (name === 'users') { return ( ) } if (name === 'file') { return ( ) } if (name === 'clipboard') { return ( ) } if (name === 'message') { return ( ) } if (name === 'chart') { return ( ) } if (name === 'shield') { return ( ) } if (name === 'settings') { return ( ) } return ( ) } function BellIcon({ className = 'size-5' }) { return ( ) } function UserIcon({ className = 'size-4' }) { return ( ) } function LogoutIcon({ className = 'size-4' }) { return ( ) } function ChevronDownIcon({ className = 'size-4' }) { return ( ) } function getInitials(name) { return String(name || 'US') .split(' ') .filter(Boolean) .slice(0, 2) .map((part) => part[0]) .join('') .toUpperCase() }