document.addEventListener('DOMContentLoaded', () => {
// Configurações
const API_URL = '/api/admin/clinics';
// Pegar Token JWT do Admin
const token = localStorage.getItem('token') || '';
// Se não tem token, redirecionar imediatamente para login
if (!token) {
window.location.href = '/login';
return;
}
const fetchOptions = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
};
// Elementos UI
const clinicsTableBody = document.getElementById('clinicsTableBody');
const addClinicBtn = document.getElementById('addClinicBtn');
const clinicModal = document.getElementById('clinicModal');
const tokenModal = document.getElementById('tokenModal');
const closeModals = document.querySelectorAll('.close-modal');
const closeTokenModal = document.querySelector('.close-token-modal');
const clinicForm = document.getElementById('clinicForm');
const generatedTokenElem = document.getElementById('generatedToken');
const copyTokenBtn = document.getElementById('copyTokenBtn');
// Stats
const totalDevicesElem = document.getElementById('totalDevices');
const activeDevicesElem = document.getElementById('activeDevices');
const blockedDevicesElem = document.getElementById('blockedDevices');
// Inicializar
loadClinics();
// ==========================================
// Carregar Clínicas
// ==========================================
async function loadClinics() {
try {
const response = await fetch(API_URL, fetchOptions);
// Se recebeu 401 ou 403, token expirou — vai para login
if (response.status === 401 || response.status === 403) {
localStorage.removeItem('token');
window.location.href = '/login';
return;
}
// Verificar se a resposta é realmente JSON (evita erro com HTML)
const contentType = response.headers.get('content-type') || '';
if (!contentType.includes('application/json')) {
throw new Error('Sessão expirada ou servidor indisponível. Faça login novamente.');
}
if (!response.ok) {
throw new Error(`Erro HTTP ${response.status}`);
}
const data = await response.json();
if (data.success) {
renderClinics(data.clinics);
updateStats(data.clinics);
} else {
showToast(data.message, 'error');
}
} catch (error) {
console.error(error);
clinicsTableBody.innerHTML = `
| ${error.message || 'Erro ao carregar dados.'} |
`;
}
}
// ==========================================
// Renderizar Tabela
// ==========================================
function renderClinics(clinics) {
if (clinics.length === 0) {
clinicsTableBody.innerHTML = `| Nenhum dispositivo cadastrado. |
`;
return;
}
clinicsTableBody.innerHTML = '';
clinics.forEach(c => {
const isAct = c.is_active;
const statusClass = isAct ? 'status-active' : 'status-inactive';
const statusIcon = isAct ? 'fa-check' : 'fa-ban';
const statusText = isAct ? 'Ativo' : 'Bloqueado';
const tr = document.createElement('tr');
tr.innerHTML = `
${statusText} |
${c.clinic_name} |
${c.pc_name || '-'} |
${c.email} |
${c.last_ip || 'Nunca conectou'} |
${c.machine_token.split('-')[0]}... |
|
`;
clinicsTableBody.appendChild(tr);
});
}
function updateStats(clinics) {
const total = clinics.length;
const active = clinics.filter(c => c.is_active).length;
const blocked = total - active;
totalDevicesElem.textContent = total;
activeDevicesElem.textContent = active;
blockedDevicesElem.textContent = blocked;
}
// ==========================================
// Cadastrar Clínica
// ==========================================
clinicForm.addEventListener('submit', async (e) => {
e.preventDefault();
const submitBtn = document.getElementById('submitBtn');
submitBtn.disabled = true;
submitBtn.innerHTML = ' Salvando...';
const formData = new FormData(clinicForm);
const bodyData = Object.fromEntries(formData.entries());
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: fetchOptions.headers,
body: JSON.stringify(bodyData)
});
const data = await response.json();
if (data.success) {
clinicModal.classList.remove('active');
clinicForm.reset();
loadClinics();
// Show Token Modal
generatedTokenElem.textContent = data.machine_token;
tokenModal.classList.add('active');
} else {
showToast(data.message, 'error');
}
} catch (error) {
showToast('Erro de conexão ao salvar', 'error');
} finally {
submitBtn.disabled = false;
submitBtn.innerHTML = ' Salvar e Gerar Token';
}
});
// ==========================================
// Toggle Status
// ==========================================
window.toggleStatus = async (id, isActive) => {
try {
const response = await fetch(`${API_URL}/${id}/status`, {
method: 'PUT',
headers: fetchOptions.headers,
body: JSON.stringify({ is_active: isActive })
});
const data = await response.json();
if(data.success) {
showToast(isActive ? 'Dispositivo Ativado' : 'Dispositivo Bloqueado', 'success');
loadClinics();
} else {
showToast(data.message, 'error');
loadClinics(); // revert UI
}
} catch (error) {
showToast('Erro ao alterar status', 'error');
loadClinics();
}
};
// ==========================================
// Deletar
// ==========================================
window.deleteClinic = async (id) => {
if(!confirm('Tem certeza que deseja excluir este dispositivo permanentemente? O Desktop perderá acesso instantaneamente.')) return;
try {
const response = await fetch(`${API_URL}/${id}`, {
method: 'DELETE',
headers: fetchOptions.headers
});
const data = await response.json();
if(data.success) {
showToast('Dispositivo removido', 'success');
loadClinics();
} else {
showToast(data.message, 'error');
}
} catch (error) {
showToast('Erro ao excluir', 'error');
}
};
// ==========================================
// UI Actions (Modals, Copy, Logout)
// ==========================================
addClinicBtn.addEventListener('click', () => clinicModal.classList.add('active'));
closeModals.forEach(btn => btn.addEventListener('click', () => {
clinicModal.classList.remove('active');
}));
closeTokenModal.addEventListener('click', () => {
tokenModal.classList.remove('active');
});
copyTokenBtn.addEventListener('click', () => {
navigator.clipboard.writeText(generatedTokenElem.textContent).then(() => {
showToast('Token copiado com sucesso!', 'success');
copyTokenBtn.innerHTML = '';
setTimeout(() => {
copyTokenBtn.innerHTML = '';
}, 2000);
});
});
document.getElementById('logoutBtn').addEventListener('click', () => {
localStorage.removeItem('token');
window.location.href = '/login';
});
function showToast(message, type = 'success') {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = `toast show ${type}`;
setTimeout(() => {
toast.className = 'toast';
}, 3000);
}
});