import React, { useEffect, useRef, useState } from 'react' import { api, getAuthToken, setAuthToken } from './api' import AvaliacaoTab from './components/AvaliacaoTab' import ElaboracaoTab from './components/ElaboracaoTab' import InicioTab from './components/InicioTab' import PesquisaTab from './components/PesquisaTab' import RepositorioTab from './components/RepositorioTab' const LOGS_PAGE_SIZE = 30 const TABS = [ { key: 'Pesquisa/Visualização', label: 'Pesquisa/Visualização' }, { key: 'Elaboração/Edição', label: 'Elaboração/Edição' }, { key: 'Avaliação', label: 'Avaliação de Imóveis' }, { key: 'Repositório de Modelos', label: 'Repositório de Modelos' }, ] export default function App() { const [activeTab, setActiveTab] = useState('') const [showStartupIntro, setShowStartupIntro] = useState(true) const [sessionId, setSessionId] = useState('') const [bootError, setBootError] = useState('') const [avaliacaoQuickLoad, setAvaliacaoQuickLoad] = useState(null) const [authLoading, setAuthLoading] = useState(true) const [authUser, setAuthUser] = useState(null) const [authError, setAuthError] = useState('') const [loginLoading, setLoginLoading] = useState(false) const [usuario, setUsuario] = useState('') const [matricula, setMatricula] = useState('') const [logsStatus, setLogsStatus] = useState(null) const [logsStatusLoading, setLogsStatusLoading] = useState(false) const [logsOpen, setLogsOpen] = useState(false) const [logsEvents, setLogsEvents] = useState([]) const [logsLoading, setLogsLoading] = useState(false) const [logsError, setLogsError] = useState('') const [logsScope, setLogsScope] = useState('') const [logsUsuario, setLogsUsuario] = useState('') const [logsPage, setLogsPage] = useState(1) const [settingsOpen, setSettingsOpen] = useState(false) const [showScrollHomeBtn, setShowScrollHomeBtn] = useState(false) const [scrollHomeBtnLeft, setScrollHomeBtnLeft] = useState(8) const headerRef = useRef(null) const settingsMenuRef = useRef(null) const isAdmin = String(authUser?.perfil || '').toLowerCase() === 'admin' const logsEnabled = Boolean(logsStatus?.enabled) const logsDisabledReason = String(logsStatus?.reason || 'Logs indisponíveis') const logsViewActive = Boolean(authUser && isAdmin && logsOpen) const logsTotalPages = Math.max(1, Math.ceil(logsEvents.length / LOGS_PAGE_SIZE)) const logsCurrentPage = Math.min(logsPage, logsTotalPages) const logsStartIndex = logsEvents.length ? (logsCurrentPage - 1) * LOGS_PAGE_SIZE : 0 const logsVisibleEvents = logsEvents.slice(logsStartIndex, logsStartIndex + LOGS_PAGE_SIZE) const logsEndIndex = logsEvents.length ? Math.min(logsStartIndex + LOGS_PAGE_SIZE, logsEvents.length) : 0 function resetToLogin(message = '') { setAuthToken('') setAuthUser(null) setAuthLoading(false) setLoginLoading(false) setSessionId('') setBootError('') setLogsStatus(null) setLogsOpen(false) setLogsEvents([]) setLogsError('') setLogsPage(1) setActiveTab('') setShowStartupIntro(true) setAuthError(message) } useEffect(() => { let mounted = true async function bootstrapAuth() { const token = getAuthToken() if (!token) { if (mounted) setAuthLoading(false) return } try { const resp = await api.authMe() if (!mounted) return setAuthUser(resp?.usuario || null) } catch { setAuthToken('') if (!mounted) return setAuthUser(null) } finally { if (mounted) setAuthLoading(false) } } void bootstrapAuth() return () => { mounted = false } }, []) useEffect(() => { function onAuthRequired(event) { const message = String(event?.detail?.message || '').trim() || 'Sessão expirada. Faça login novamente.' resetToLogin(message) } if (typeof window !== 'undefined') { window.addEventListener('mesa:auth-required', onAuthRequired) return () => window.removeEventListener('mesa:auth-required', onAuthRequired) } return undefined }, []) useEffect(() => { let mounted = true if (!authUser) { setSessionId('') setBootError('') return () => { mounted = false } } setBootError('') api.createSession() .then((resp) => { if (!mounted) return setSessionId(resp.session_id) setBootError('') }) .catch((err) => { if (!mounted) return if (Number(err?.status) === 401) return setBootError(err.message || 'Falha ao criar sessão') }) return () => { mounted = false } }, [authUser]) useEffect(() => { if (!authUser || !isAdmin) { setLogsStatus(null) setLogsOpen(false) setLogsEvents([]) setLogsError('') setLogsPage(1) setLogsStatusLoading(false) setLogsLoading(false) return } void carregarLogsStatus() }, [authUser, isAdmin]) useEffect(() => { if (!logsEvents.length && logsPage !== 1) { setLogsPage(1) return } if (logsPage > logsTotalPages) { setLogsPage(logsTotalPages) } }, [logsEvents.length, logsPage, logsTotalPages]) useEffect(() => { if (!settingsOpen) return undefined function onPointerDown(event) { if (!settingsMenuRef.current) return if (!settingsMenuRef.current.contains(event.target)) { setSettingsOpen(false) } } document.addEventListener('mousedown', onPointerDown) return () => document.removeEventListener('mousedown', onPointerDown) }, [settingsOpen]) useEffect(() => { if (!authUser) { setSettingsOpen(false) } }, [authUser]) useEffect(() => { if (typeof window === 'undefined') return undefined if (!authUser) { setShowScrollHomeBtn(false) setScrollHomeBtnLeft(8) return undefined } function resolveHomeButtonLeft() { const buttonSize = 42 const navAnchor = document.querySelector('.elaboracao-side-nav-item') if (navAnchor && typeof navAnchor.getBoundingClientRect === 'function') { const rect = navAnchor.getBoundingClientRect() return Math.max(8, rect.left + ((rect.width - buttonSize) / 2)) } const shell = document.querySelector('.app-shell') if (shell && typeof shell.getBoundingClientRect === 'function') { const rect = shell.getBoundingClientRect() return Math.max(8, rect.left) } return 8 } function updateScrollHomeVisibility() { const headerEl = headerRef.current if (!headerEl) { setShowScrollHomeBtn(false) return } const rect = headerEl.getBoundingClientRect() const shouldShow = rect.bottom <= 0 const nextLeft = resolveHomeButtonLeft() setShowScrollHomeBtn((current) => (current === shouldShow ? current : shouldShow)) setScrollHomeBtnLeft((current) => (Math.abs(current - nextLeft) < 0.5 ? current : nextLeft)) } updateScrollHomeVisibility() window.addEventListener('scroll', updateScrollHomeVisibility, { passive: true }) window.addEventListener('resize', updateScrollHomeVisibility) return () => { window.removeEventListener('scroll', updateScrollHomeVisibility) window.removeEventListener('resize', updateScrollHomeVisibility) } }, [authUser]) async function onSubmitLogin(event) { event.preventDefault() setAuthError('') setBootError('') setLoginLoading(true) try { const resp = await api.authLogin(usuario, matricula) setAuthToken(resp?.token || '') setAuthUser(resp?.usuario || null) setUsuario('') setMatricula('') } catch (err) { setAuthError(err.message || 'Falha no login') setAuthUser(null) setAuthToken('') } finally { setLoginLoading(false) setAuthLoading(false) } } async function onLogout() { setSettingsOpen(false) try { await api.authLogout() } catch { // Ignore falha de logout remoto para garantir limpeza local. } resetToLogin('') } async function carregarLogsStatus() { if (!isAdmin) return setLogsStatusLoading(true) try { const resp = await api.logsStatus() setLogsStatus(resp || null) } catch (err) { setLogsStatus({ enabled: false, backend: 'disabled', reason: err.message || 'Falha ao carregar status de logs.', }) } finally { setLogsStatusLoading(false) } } async function carregarEventosLogs() { if (!isAdmin || !logsEnabled) return setLogsLoading(true) setLogsError('') try { const resp = await api.logsEvents({ scope: logsScope, usuario: logsUsuario, limit: 1000 }) setLogsEvents(Array.isArray(resp?.events) ? resp.events : []) setLogsPage(1) } catch (err) { setLogsError(err.message || 'Falha ao carregar logs.') setLogsEvents([]) setLogsPage(1) } finally { setLogsLoading(false) } } async function onToggleLogs() { if (!isAdmin) return if (logsOpen) { setLogsOpen(false) return } setLogsOpen(true) if (!logsEnabled) return await carregarEventosLogs() } function onCloseLogsView() { setLogsOpen(false) } function onUsarModeloEmAvaliacao(modelo) { const modeloId = String(modelo?.id || '').trim() if (!modeloId) return setAvaliacaoQuickLoad({ requestKey: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, modeloId, modeloArquivo: String(modelo?.arquivo || '').trim(), nomeModelo: String(modelo?.nome_modelo || modelo?.arquivo || modeloId), }) setActiveTab('Avaliação') setLogsOpen(false) setShowStartupIntro(false) } function onScrollToHeader() { if (typeof window === 'undefined') return const headerEl = headerRef.current if (!headerEl) return const top = Math.max(0, window.scrollY + headerEl.getBoundingClientRect().top - 8) window.scrollTo({ top, behavior: 'smooth' }) } return (
{authUser ? (
{settingsOpen ? (
Usuário: {authUser.nome || authUser.usuario} ({authUser.perfil || 'viewer'})
{isAdmin ? ( ) : null}
) : null}
) : null}
{authUser && showScrollHomeBtn ? ( ) : null} {authLoading ?
Validando autenticação...
: null} {!authLoading && !authUser ? (

Entrar na MESA

Usuário: primeiro nome sem acentos e em minúsculo. Senha: matrícula sem dígito.

setUsuario(event.target.value)} autoComplete="off" disabled={loginLoading} />
setMatricula(event.target.value)} autoComplete="off" disabled={loginLoading} />
{authError ?
{authError}
: null}
) : null} {authUser ? ( logsViewActive ? (

Logs

Para voltar ao app, clique em "Fechar logs".

{logsStatus?.backend === 'hf_dataset' ? 'Origem: Dataset HF' : 'Origem: indisponível'} {logsStatus?.revision ? Revisão: {String(logsStatus.revision).slice(0, 8)} : null}
{!logsEnabled ? (
{logsDisabledReason}
) : ( <>
setLogsUsuario(event.target.value)} placeholder="filtrar por usuário" autoComplete="off" />
{logsError ?
{logsError}
: null}
{logsVisibleEvents.map((item) => ( ))} {!logsEvents.length ? ( ) : null}
Timestamp Usuário Perfil Escopo Ação Status Detalhes
{item.ts || '-'} {item.usuario || '-'} {item.perfil || '-'} {item.scope || '-'} {item.action || '-'} {item.status || '-'} {JSON.stringify(item.details || {})}
{logsLoading ? 'Carregando logs...' : 'Nenhum log encontrado para os filtros.'}
{logsEvents.length ? `Exibindo ${logsStartIndex + 1}-${logsEndIndex} de ${logsEvents.length}` : 'Exibindo 0 de 0'}
Página {logsCurrentPage} de {logsTotalPages}
)}
) : ( <> {bootError ?
Falha ao criar sessão: {bootError}
: null} {showStartupIntro ? (
) : null} ) ) : null}
) }