import { Component, lazy, Suspense, useCallback, useEffect, useMemo, useState } from 'react' import { AppShell } from './components/AppShell.jsx' import { canAccess } from './config/permissions.js' import { useAuth } from './hooks/useAuth.js' import { ForgotPasswordPage, LoginPage, RegisterPage } from './pages/AuthPages.jsx' import { NotFoundPage } from './pages/NotFoundPage.jsx' import { patientRepository } from './repositories/patientRepository.js' const AgendaPage = lazyPage(() => import('./pages/AgendaPage.jsx'), 'AgendaPage') const AnalyticsPage = lazyPage(() => import('./pages/AnalyticsPage.jsx'), 'AnalyticsPage') const HomePage = lazyPage(() => import('./pages/HomePage.jsx'), 'HomePage') const MedicalRecordsPage = lazyPage(() => import('./pages/MedicalRecordsPage.jsx'), 'MedicalRecordsPage') const MessagesPage = lazyPage(() => import('./pages/MessagesPage.jsx'), 'MessagesPage') const PatientDetailPage = lazyPage(() => import('./pages/PatientsPage.jsx'), 'PatientDetailPage') const PatientsPage = lazyPage(() => import('./pages/PatientsPage.jsx'), 'PatientsPage') const ProfilePage = lazyPage(() => import('./pages/ProfilePage.jsx'), 'ProfilePage') const ReportsPage = lazyPage(() => import('./pages/ReportsPage.jsx'), 'ReportsPage') const SettingsPage = lazyPage(() => import('./pages/SettingsPage.jsx'), 'SettingsPage') const UsersPage = lazyPage(() => import('./pages/UsersPage.jsx'), 'UsersPage') const VisitsPage = lazyPage(() => import('./pages/VisitsPage.jsx'), 'VisitsPage') const PANEL_PATHS = ['/inicio', '/home', '/dashboard'] const ROLE_HOME_PATHS = { medico: '/agenda', secretaria: '/agenda', } function lazyPage(loader, exportName) { return lazy(() => loader().then((module) => ({ default: module[exportName] }))) } function App() { const [location, setLocation] = useState(() => readLocation()) const { isAuthenticated, role, loading: authLoading } = useAuth() const navigate = useCallback((to, options = {}) => { if (options.replace) { window.history.replaceState({}, '', to) } else { window.history.pushState({}, '', to) } setLocation(readLocation()) const hash = to.split('#')[1] window.requestAnimationFrame(() => { if (hash) { document.getElementById(hash)?.scrollIntoView({ block: 'start' }) } else { window.scrollTo({ left: 0, top: 0 }) } }) }, []) useEffect(() => { function handlePopState() { setLocation(readLocation()) } window.addEventListener('popstate', handlePopState) return () => window.removeEventListener('popstate', handlePopState) }, []) const route = useMemo( () => resolveRoute(location.pathname, navigate, role), [location.pathname, navigate, role], ) // Tela de carregamento enquanto busca o role do usuário if (authLoading) { return (

Carregando...

) } // Rotas públicas (sem shell) if (!route.withShell) { return {route.element} } // Usuário não autenticado if (!isAuthenticated) { return } // Usuário autenticado mas sem permissão para a rota if (!role || !canAccess(role, location.pathname)) { const roleHomePath = ROLE_HOME_PATHS[role] if (roleHomePath && PANEL_PATHS.includes(location.pathname)) { navigate(roleHomePath, { replace: true }) return null } return ( ) } return ( {route.element} ) } class RouteErrorBoundary extends Component { state = { error: null } static getDerivedStateFromError(error) { return { error } } componentDidUpdate(previousProps) { if (previousProps.resetKey !== this.props.resetKey && this.state.error) { this.setState({ error: null }) } } render() { if (this.state.error) { return } return this.props.children } } function RouteSuspense({ children, resetKey }) { return ( }> {children} ) } function RouteFallback() { return (

Carregando modulo...

) } function RouteErrorFallback() { return (

Não foi possível carregar esta tela

Ocorreu um erro ao abrir o modulo. Recarregue a pagina e tente novamente.

) } function resolveRoute(pathname, navigate, role) { if (pathname === '/' || pathname === '/login') { return { element: , title: 'Login', withShell: false, } } if (pathname === '/cadastro') { return { element: , title: 'Cadastro', withShell: false, } } if (pathname === '/recuperar-senha') { return { element: , title: 'Recuperar senha', withShell: false, } } if (pathname === '/inicio' || pathname === '/home' || pathname === '/dashboard') { return { element: , title: 'Painel', withShell: true, } } if (pathname === '/agenda') { return { element: , title: 'Agenda', withShell: true, } } if (pathname === '/pacientes') { return { element: , title: 'Pacientes', withShell: true, } } if (pathname === '/prontuario') { return { element: , title: 'Prontuário', withShell: true, } } if (pathname === '/prontuario/novo') { return { element: , title: 'Novo prontuário', withShell: true, } } if (pathname.startsWith('/prontuario/')) { const [, , recordId, action] = pathname.split('/') return { element: , title: action === 'editar' ? 'Editar prontuário' : 'Prontuário', withShell: true, } } if (pathname.startsWith('/pacientes/')) { const patientId = pathname.split('/')[2] return { element: , title: 'Paciente', withShell: true, } } if (pathname === '/consultas') { return { element: , title: 'Consultas', withShell: true, } } if (pathname === '/laudos') { return { element: , title: 'Relatórios', withShell: true, } } if (pathname === '/relatorios') { return { element: , title: 'Analytics', withShell: true, } } if (pathname === '/camunicacao') { navigate('/comunicacao', { replace: true }) return { element: , title: 'Comunicação', withShell: true, } } if (pathname === '/comunicacao' || pathname === '/mensagens') { return { element: , title: 'Comunicação', withShell: true, } } if (pathname === '/usuarios') { return { element: , title: 'Usuários', withShell: true, } } if (pathname === '/perfil') { return { element: , title: 'Perfil', withShell: true, } } if (pathname === '/configuracoes' || pathname === '/config') { return { element: , title: 'Configurações', withShell: true, } } return { element: , title: 'Página não encontrada', withShell: true, } } function PatientDetailRoute({ navigate, patientId, role }) { const [patient, setPatient] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { let active = true patientRepository .getById(patientId) .then((data) => { if (active) setPatient(data) }) .finally(() => { if (active) setLoading(false) }) return () => { active = false } }, [patientId]) if (loading) { return
Carregando paciente...
} return patient ? ( ) : ( ) } function UnauthorizedPage({ navigate }) { return (

🔒

Acesso não permitido

Você não tem permissão para acessar esta página.

) } function readLocation() { return { pathname: normalizePath(window.location.pathname), search: window.location.search, } } function normalizePath(pathname) { if (!pathname || pathname === '/') { return '/' } return pathname.replace(/\/+$/, '') } export default App