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();