const tableBody = document.getElementById('devicesTable'); const refreshBtn = document.getElementById('refreshBtn'); const statusMessage = document.getElementById('statusMessage'); async function fetchDevices() { setStatus('Cargando dispositivos...'); try { const response = await fetch('/api/devices'); if (!response.ok) { throw new Error('Error ' + response.status); } const { devices } = await response.json(); renderTable(devices || []); setStatus('Actualizado ' + new Date().toLocaleTimeString()); } catch (error) { console.error(error); setStatus('No se pudo cargar el listado'); } } function renderTable(devices) { tableBody.innerHTML = ''; if (!devices.length) { tableBody.innerHTML = 'Sin registros'; return; } devices.sort((a, b) => (a.lastSeen || '').localeCompare(b.lastSeen || '') * -1); for (const device of devices) { const tr = document.createElement('tr'); if (device.blocked) { tr.classList.add('blocked'); } const alias = device.alias && device.alias.trim().length ? device.alias : 'Sin alias'; const verificationStatus = device.verification && device.verification.status ? device.verification.status : 'pending'; const needsVerification = verificationStatus !== 'verified'; const verificationText = needsVerification ? `Pendiente - Token cliente: ${device.verification && device.verification.clientPart ? device.verification.clientPart : 'N/A'}` : `Verificado ${device.verification.verifiedAt ? `(${formatDate(device.verification.verifiedAt)})` : ''}`; const statusLabel = device.blocked ? 'Bloqueado' : needsVerification ? 'Pendiente token' : 'Activo'; const actions = [``]; if (needsVerification) { actions.push(''); } actions.push(device.blocked ? '' : ''); actions.push(''); tr.innerHTML = `
${alias}
${device.deviceName || '(sin nombre)'}
${device.deviceId} ${[device.manufacturer, device.model].filter(Boolean).join(' ')} ${device.appVersionName || ''} (${device.appVersionCode || ''}) ${device.ip || '-'} ${formatCountry(device.country)} ${verificationText} ${formatDate(device.lastSeen)} ${statusLabel} ${actions.join(' ')} `; tr.dataset.deviceId = device.deviceId; tableBody.appendChild(tr); } } function formatDate(value) { if (!value) return '-'; const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString(); } function formatCountry(value) { if (!value || value === 'N/A') { return '-'; } return value; } async function blockDevice(deviceId) { const reason = prompt('Motivo del bloqueo (opcional):'); await fetch(`/api/devices/${encodeURIComponent(deviceId)}/block`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason }) }); await fetchDevices(); } async function unblockDevice(deviceId) { await fetch(`/api/devices/${encodeURIComponent(deviceId)}/unblock`, { method: 'POST' }); await fetchDevices(); } async function deleteDevice(deviceId) { const confirmation = confirm('¿Seguro que quieres borrar este dispositivo? Generará un nuevo token cuando se registre de nuevo.'); if (!confirmation) { return; } const response = await fetch(`/api/devices/${encodeURIComponent(deviceId)}`, { method: 'DELETE' }); if (!response.ok) { alert('No se pudo borrar el dispositivo'); return; } await fetchDevices(); } async function verifyDevice(deviceId) { const clientTokenPart = prompt('Introduce el token que aparece en el dispositivo:'); if (clientTokenPart === null) { return; } const adminTokenPart = prompt('Introduce el token recibido en Telegram:'); if (adminTokenPart === null) { return; } const response = await fetch(`/api/devices/${encodeURIComponent(deviceId)}/verify`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ clientTokenPart, adminTokenPart }) }); if (!response.ok) { const payload = await response.json().catch(() => ({})); alert(payload.error || 'No se pudo verificar el token'); return; } await fetchDevices(); } async function updateAlias(deviceId) { const alias = prompt('Nuevo alias para el dispositivo:'); if (alias === null) { return; } await fetch(`/api/devices/${encodeURIComponent(deviceId)}/alias`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ alias }) }); await fetchDevices(); } function setStatus(message) { statusMessage.textContent = message; } refreshBtn.addEventListener('click', fetchDevices); tableBody.addEventListener('click', async (event) => { const button = event.target.closest('button'); if (!button) return; const tr = button.closest('tr'); const deviceId = tr && tr.dataset.deviceId; if (!deviceId) return; const action = button.dataset.action; try { if (action === 'block') { await blockDevice(deviceId); } else if (action === 'unblock') { await unblockDevice(deviceId); } else if (action === 'alias') { await updateAlias(deviceId); } else if (action === 'verify') { await verifyDevice(deviceId); } else if (action === 'delete') { await deleteDevice(deviceId); } } catch (error) { console.error(error); alert('Operación fallida'); } }); fetchDevices();