feat: reestruturacao de menus na sidebar, niveis de acesso e migracao para postgresql/dragonflydb
continuous-integration/webhook Deploy concluido (rx.scoreodonto.com)
continuous-integration/webhook Deploy concluido (rx.scoreodonto.com)
This commit is contained in:
@@ -5,6 +5,20 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gerenciamento de Clínicas - RF Dental</title>
|
||||
|
||||
<script>
|
||||
// Redirecionar se não estiver autenticado ou não for administrador
|
||||
if (!localStorage.getItem('auth_token')) {
|
||||
window.location.replace('/login');
|
||||
} else if (localStorage.getItem('is_admin') !== 'true') {
|
||||
window.location.replace('/');
|
||||
} else {
|
||||
// Adiciona classe de admin no body para que os estilos de admin sejam exibidos
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.body.classList.add('is-admin');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Fontes -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
@@ -28,15 +42,41 @@
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<a href="/" class="nav-item">
|
||||
<div class="nav-section-title">Menu Principal</div>
|
||||
<a href="/" class="nav-item" id="menu-dashboard">
|
||||
<i class="fa-solid fa-chart-line"></i> Dashboard
|
||||
</a>
|
||||
<a href="/clients" class="nav-item">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
<a href="/?action=new-patient" class="nav-item" id="menu-new-patient" onclick="if(window.location.pathname === '/') { openCreatePatientModal(); return false; }">
|
||||
<i class="fa-solid fa-user-plus"></i> Novo Paciente
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item active">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
<a href="/?action=sync-upload" class="nav-item" id="menu-upload" onclick="if(window.location.pathname === '/') { openSyncModal('upload'); return false; }">
|
||||
<i class="fa-solid fa-upload"></i> Enviar Imagens
|
||||
</a>
|
||||
<a href="/?action=settings" class="nav-item" id="menu-settings" onclick="if(window.location.pathname === '/') { openSettingsModal(); return false; }">
|
||||
<i class="fa-solid fa-user-gear"></i> Minha Conta
|
||||
</a>
|
||||
|
||||
<div class="admin-only">
|
||||
<div class="nav-section-title">Área Administrativa</div>
|
||||
<a href="/clients" class="nav-item" id="menu-clients">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item active" id="menu-clinics">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
</a>
|
||||
<a href="/?action=users" class="nav-item" id="menu-users" onclick="if(window.location.pathname === '/') { openUserManagementModal(); return false; }">
|
||||
<i class="fa-solid fa-users"></i> Gerenciar Usuários
|
||||
</a>
|
||||
<a href="/?action=sync-devices" class="nav-item" id="menu-sync" onclick="if(window.location.pathname === '/') { openSyncModal('devices'); return false; }">
|
||||
<i class="fa-solid fa-rotate"></i> Sincronização
|
||||
</a>
|
||||
<a href="/?action=plugins" class="nav-item" id="menu-plugins" onclick="if(window.location.pathname === '/') { openPluginsModal(); return false; }">
|
||||
<i class="fa-solid fa-plug"></i> Plugins / Wasabi
|
||||
</a>
|
||||
<a href="/reset" class="nav-item" id="menu-reset" style="color: #dc2626;">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i> Zerar Sistema
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
|
||||
@@ -4,6 +4,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// Pegar Token JWT do Admin
|
||||
const token = localStorage.getItem('auth_token') || '';
|
||||
const isAdmin = localStorage.getItem('is_admin') === 'true';
|
||||
|
||||
// Se não tem token, redirecionar imediatamente para login
|
||||
if (!token) {
|
||||
@@ -11,6 +12,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Se não for administrador, redirecionar imediatamente para a home
|
||||
if (!isAdmin) {
|
||||
window.location.href = '/';
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchOptions = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
+14
-13
@@ -78,15 +78,11 @@ async function verifyAuth() {
|
||||
}
|
||||
|
||||
function updateAdminMenuVisibility(isAdmin) {
|
||||
// Esconder links não autorizados da Sidebar
|
||||
const connectionsLink = document.querySelector('.sidebar-nav .nav-item[href="/clients"]');
|
||||
const clinicsLink = document.querySelector('.sidebar-nav .nav-item[href="/admin-clinics"]');
|
||||
if (connectionsLink) connectionsLink.style.display = isAdmin ? 'flex' : 'none';
|
||||
if (clinicsLink) clinicsLink.style.display = isAdmin ? 'flex' : 'none';
|
||||
|
||||
// Esconder botão de gerenciamento de usuários na toolbar
|
||||
const btnUserManagement = document.getElementById('btnUserManagement');
|
||||
if (btnUserManagement) btnUserManagement.style.display = isAdmin ? 'flex' : 'none';
|
||||
if (isAdmin) {
|
||||
document.body.classList.add('is-admin');
|
||||
} else {
|
||||
document.body.classList.remove('is-admin');
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWithAuth(url, options = {}) {
|
||||
@@ -189,7 +185,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (action === 'new-patient') window.openCreatePatientModal();
|
||||
else if (action === 'settings') window.openSettingsModal();
|
||||
else if (action === 'plugins') window.openPluginsModal();
|
||||
else if (action === 'sync') window.openSyncModal();
|
||||
else if (action === 'sync-devices') window.openSyncModal('devices');
|
||||
else if (action === 'sync-upload') window.openSyncModal('upload');
|
||||
else if (action === 'sync') window.openSyncModal('devices');
|
||||
else if (action === 'users') window.openUserManagementModal();
|
||||
|
||||
// Remove querystring to prevent reopening on reload
|
||||
window.history.replaceState({}, document.title, window.location.pathname);
|
||||
@@ -1505,7 +1504,7 @@ window.triggerSync = triggerSync;
|
||||
|
||||
let selectedUploadFiles = [];
|
||||
|
||||
function openSyncModal() {
|
||||
function openSyncModal(defaultTab = 'devices') {
|
||||
const modal = document.getElementById('syncModal');
|
||||
if (!modal) return;
|
||||
|
||||
@@ -1513,13 +1512,15 @@ function openSyncModal() {
|
||||
modal.style.display = 'flex';
|
||||
|
||||
// Resetar abas
|
||||
switchSyncTab('devices');
|
||||
switchSyncTab(defaultTab);
|
||||
|
||||
// Limpar formulário de upload
|
||||
resetManualUploadForm();
|
||||
|
||||
// Carregar dados
|
||||
loadSyncDevices();
|
||||
if (defaultTab === 'devices') {
|
||||
loadSyncDevices();
|
||||
}
|
||||
refreshUploadPatients();
|
||||
|
||||
// Escuta de clique fora para fechar modal
|
||||
|
||||
@@ -179,9 +179,16 @@
|
||||
|
||||
</style>
|
||||
<script>
|
||||
// Redirecionar se não estiver autenticado
|
||||
// Redirecionar se não estiver autenticado ou não for administrador
|
||||
if (!localStorage.getItem('auth_token')) {
|
||||
window.location.href = '/login';
|
||||
window.location.replace('/login');
|
||||
} else if (localStorage.getItem('is_admin') !== 'true') {
|
||||
window.location.replace('/');
|
||||
} else {
|
||||
// Adiciona classe de admin no body para que os estilos de admin sejam exibidos
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.body.classList.add('is-admin');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
@@ -196,15 +203,41 @@
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<a href="/" class="nav-item">
|
||||
<div class="nav-section-title">Menu Principal</div>
|
||||
<a href="/" class="nav-item" id="menu-dashboard">
|
||||
<i class="fa-solid fa-chart-line"></i> Dashboard
|
||||
</a>
|
||||
<a href="/clients" class="nav-item active">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
<a href="/?action=new-patient" class="nav-item" id="menu-new-patient" onclick="if(window.location.pathname === '/') { openCreatePatientModal(); return false; }">
|
||||
<i class="fa-solid fa-user-plus"></i> Novo Paciente
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
<a href="/?action=sync-upload" class="nav-item" id="menu-upload" onclick="if(window.location.pathname === '/') { openSyncModal('upload'); return false; }">
|
||||
<i class="fa-solid fa-upload"></i> Enviar Imagens
|
||||
</a>
|
||||
<a href="/?action=settings" class="nav-item" id="menu-settings" onclick="if(window.location.pathname === '/') { openSettingsModal(); return false; }">
|
||||
<i class="fa-solid fa-user-gear"></i> Minha Conta
|
||||
</a>
|
||||
|
||||
<div class="admin-only">
|
||||
<div class="nav-section-title">Área Administrativa</div>
|
||||
<a href="/clients" class="nav-item active" id="menu-clients">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item" id="menu-clinics">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
</a>
|
||||
<a href="/?action=users" class="nav-item" id="menu-users" onclick="if(window.location.pathname === '/') { openUserManagementModal(); return false; }">
|
||||
<i class="fa-solid fa-users"></i> Gerenciar Usuários
|
||||
</a>
|
||||
<a href="/?action=sync-devices" class="nav-item" id="menu-sync" onclick="if(window.location.pathname === '/') { openSyncModal('devices'); return false; }">
|
||||
<i class="fa-solid fa-rotate"></i> Sincronização
|
||||
</a>
|
||||
<a href="/?action=plugins" class="nav-item" id="menu-plugins" onclick="if(window.location.pathname === '/') { openPluginsModal(); return false; }">
|
||||
<i class="fa-solid fa-plug"></i> Plugins / Wasabi
|
||||
</a>
|
||||
<a href="/reset" class="nav-item" id="menu-reset" style="color: #dc2626;">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i> Zerar Sistema
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
|
||||
@@ -21,15 +21,41 @@
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<a href="/" class="nav-item active">
|
||||
<div class="nav-section-title">Menu Principal</div>
|
||||
<a href="/" class="nav-item active" id="menu-dashboard" onclick="if(window.location.pathname === '/') { showView('gallery'); return false; }">
|
||||
<i class="fa-solid fa-chart-line"></i> Dashboard
|
||||
</a>
|
||||
<a href="/clients" class="nav-item">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
<a href="#" class="nav-item" id="menu-new-patient" onclick="openCreatePatientModal(); return false;">
|
||||
<i class="fa-solid fa-user-plus"></i> Novo Paciente
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
<a href="#" class="nav-item" id="menu-upload" onclick="openSyncModal('upload'); return false;">
|
||||
<i class="fa-solid fa-upload"></i> Enviar Imagens
|
||||
</a>
|
||||
<a href="#" class="nav-item" id="menu-settings" onclick="openSettingsModal(); return false;">
|
||||
<i class="fa-solid fa-user-gear"></i> Minha Conta
|
||||
</a>
|
||||
|
||||
<div class="admin-only">
|
||||
<div class="nav-section-title">Área Administrativa</div>
|
||||
<a href="/clients" class="nav-item" id="menu-clients">
|
||||
<i class="fa-solid fa-network-wired"></i> Conexões
|
||||
</a>
|
||||
<a href="/admin-clinics" class="nav-item" id="menu-clinics">
|
||||
<i class="fa-solid fa-hospital"></i> Clínicas e Acessos
|
||||
</a>
|
||||
<a href="#" class="nav-item" id="menu-users" onclick="openUserManagementModal(); return false;">
|
||||
<i class="fa-solid fa-users"></i> Gerenciar Usuários
|
||||
</a>
|
||||
<a href="#" class="nav-item" id="menu-sync" onclick="openSyncModal('devices'); return false;">
|
||||
<i class="fa-solid fa-rotate"></i> Sincronização
|
||||
</a>
|
||||
<a href="#" class="nav-item" id="menu-plugins" onclick="openPluginsModal(); return false;">
|
||||
<i class="fa-solid fa-plug"></i> Plugins / Wasabi
|
||||
</a>
|
||||
<a href="/reset" class="nav-item" id="menu-reset" style="color: #dc2626;">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i> Zerar Sistema
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
@@ -75,8 +101,8 @@
|
||||
<!-- Scrollable content area -->
|
||||
<div class="content-scroll">
|
||||
|
||||
<!-- Toolbar de Filtros e Ações Rápidas (Migradas da Sidebar) -->
|
||||
<div class="toolbar glass-card" style="margin-bottom: 24px; padding: 16px; display: flex; gap: 16px; align-items: center; justify-content: space-between; flex-wrap: wrap; background: rgba(255, 255, 255, 0.4); border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 12px; box-shadow: var(--shadow-sm);">
|
||||
<!-- Toolbar de Filtros e Ações Rápidas -->
|
||||
<div class="toolbar glass-card" style="margin-bottom: 24px; padding: 16px; display: flex; gap: 16px; align-items: center; background: rgba(255, 255, 255, 0.4); border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 12px; box-shadow: var(--shadow-sm);">
|
||||
<div class="toolbar-left" style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;">
|
||||
<!-- Filtro de Clientes -->
|
||||
<select id="clientFilter" class="client-filter" style="padding: 10px 16px; border-radius: 10px; border: 1px solid var(--border-color); background: var(--bg-surface); color: var(--text-primary); font-size: 0.95rem; font-weight: 500; outline: none; min-width: 200px; cursor: pointer;">
|
||||
@@ -87,27 +113,6 @@
|
||||
👁️ <span id="toggleText">Ocultas</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="toolbar-right" style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap;">
|
||||
<button class="btn btn-primary" onclick="openCreatePatientModal()" style="padding: 10px 16px; border-radius: 10px; font-weight: 600; font-size: 0.95rem; background: var(--primary-color); color: white; border: none; cursor: pointer; display: flex; align-items: center; gap: 6px; box-shadow: 0 4px 10px rgba(79, 70, 229, 0.2);">
|
||||
➕ Novo Paciente
|
||||
</button>
|
||||
<button id="btnUserManagement" class="btn btn-secondary" onclick="openUserManagementModal()" title="Gerenciar Usuários" style="display: none; padding: 10px 16px; border-radius: 10px; font-weight: 500; font-size: 0.95rem; border: 1px solid var(--border-color); background: var(--bg-surface); color: var(--text-primary); cursor: pointer; align-items: center; gap: 6px;">
|
||||
👥 Gerenciar Usuários
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="openSettingsModal()" title="Configurações" style="padding: 10px 16px; border-radius: 10px; font-weight: 500; font-size: 0.95rem; border: 1px solid var(--border-color); background: var(--bg-surface); color: var(--text-primary); cursor: pointer; display: flex; align-items: center; gap: 6px;">
|
||||
⚙️ Configurações
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="openPluginsModal()" title="Plugins / Wasabi" style="padding: 10px 16px; border-radius: 10px; font-weight: 500; font-size: 0.95rem; border: 1px solid var(--border-color); background: var(--bg-surface); color: var(--text-primary); cursor: pointer; display: flex; align-items: center; gap: 6px;">
|
||||
🔌 Plugins / Wasabi
|
||||
</button>
|
||||
<button class="btn btn-secondary" onclick="openSyncModal()" title="Sincronização" style="padding: 10px 16px; border-radius: 10px; font-weight: 500; font-size: 0.95rem; border: 1px solid var(--border-color); background: var(--bg-surface); color: var(--text-primary); cursor: pointer; display: flex; align-items: center; gap: 6px;">
|
||||
🔄 Sincronização
|
||||
</button>
|
||||
<a href="/reset" class="btn btn-danger" title="Zerar Sistema" style="padding: 10px 16px; border-radius: 10px; font-weight: 500; font-size: 0.95rem; background: #fee2e2; color: #dc2626; border: 1px solid #fecaca; text-decoration: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;">
|
||||
⚠️ Zerar Sistema
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
|
||||
@@ -942,3 +942,41 @@ body {
|
||||
max-height: 95vh;
|
||||
}
|
||||
}
|
||||
|
||||
/* RF Dental Premium Sidebar Menus Additions */
|
||||
.nav-section-title {
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.2px;
|
||||
font-weight: 700;
|
||||
color: var(--text-secondary);
|
||||
padding: 12px 16px 4px 16px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* Ocultação inicial de elementos administrativos */
|
||||
.admin-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Exibição quando autenticado como admin */
|
||||
body.is-admin .admin-only {
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Responsividade mobile para o agrupamento admin */
|
||||
@media (max-width: 768px) {
|
||||
.nav-section-title {
|
||||
display: none !important;
|
||||
}
|
||||
body.is-admin .admin-only {
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
gap: 16px !important;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user