diff --git a/public/js/settings.js b/public/js/settings.js
index 27b5e2c..32f67e5 100644
--- a/public/js/settings.js
+++ b/public/js/settings.js
@@ -246,18 +246,33 @@ async function loadBans() {
const bans = await res.json();
if (!bans.length) { el.innerHTML = 'Активных блокировок нет'; return; }
el.innerHTML = bans.map(b => `
-
+
${esc(b.ip)} — ${esc(b.reason)} до ${new Date(b.banned_until).toLocaleString('ru')}
`).join('');
}
-document.getElementById('bansList').addEventListener('click', async e => {
+async function doUnban(ip) {
+ const res = await fetch(`${API}/api/bans/${encodeURIComponent(ip)}`, { method: 'DELETE', headers: hdr() });
+ if (res.ok) { showToast('IP разблокирован: ' + ip); loadBans(); }
+ else showToast('Ошибка разблокировки');
+}
+
+document.getElementById('bansList').addEventListener('click', e => {
const ip = e.target.closest('[data-unban]')?.dataset.unban;
if (!ip) return;
- const res = await fetch(`${API}/api/bans/${encodeURIComponent(ip)}`, { method: 'DELETE', headers: hdr() });
- if (res.ok) { showToast('IP разблокирован'); loadBans(); }
- else showToast('Ошибка разблокировки');
+ const chip = e.target.closest('[data-chip]');
+ if (chip.dataset.confirming) return;
+ chip.dataset.confirming = '1';
+ chip.style.background = 'rgba(239,68,68,.08)';
+ e.target.outerHTML = `
+
+ Убрать из блокировки?
+
+
+ `;
+ chip.querySelector('[data-unban-yes]').addEventListener('click', () => doUnban(ip));
+ chip.querySelector('[data-unban-no]').addEventListener('click', () => loadBans());
});
document.getElementById('backupBtn').addEventListener('click', downloadBackup);