Files
2026-10-13 18:10:02 +03:00

92 lines
4.6 KiB
JavaScript

(function (window, document) {
'use strict';
var A = window.Adminx || (window.Adminx = {});
var root = document.querySelector('[data-attention-root]');
if (!root) return;
var endpoint = root.dataset.attentionUrl;
var storageKey = 'ave.attention.' + endpoint + '.' + root.dataset.attentionUser;
var timer = null, busy = false, stopped = false, lastRequest = 0, seen = {};
try { seen = JSON.parse(sessionStorage.getItem(storageKey) || '{}') || {}; } catch (e) {}
function saveSeen() { try { sessionStorage.setItem(storageKey, JSON.stringify(seen)); } catch (e) {} }
function update(payload) {
var present = {};
payload.items.forEach(function (item) {
present[item.key] = true;
var baseline = seen[item.key];
var arriving = item.available && baseline && (item.latest_id > baseline.latest_id || item.count > baseline.count);
if (item.available) {
seen[item.key] = { latest_id: Math.max(item.latest_id, baseline ? baseline.latest_id : 0), count: item.count };
}
document.querySelectorAll('[data-attention-key]').forEach(function (el) {
if (el.dataset.attentionKey !== item.key) return;
el.hidden = false;
el.href = item.url;
el.classList.toggle('has-pending', item.available && item.count > 0);
el.classList.toggle('is-stale', !item.available);
var count = el.querySelector('[data-attention-count]');
if (count) count.textContent = item.available ? (el.classList.contains('attention-shortcut') && item.count > 99 ? '99+' : item.count) : '\u2014';
var wait = el.querySelector('[data-attention-wait]');
if (wait) wait.textContent = item.wait;
if (el.classList.contains('attention-shortcut')) {
var label = item.title + ': ' + (item.available ? item.count : '\u2014') + ' \u00b7 ' + item.wait;
el.setAttribute('aria-label', label);
el.setAttribute('data-tooltip', label);
}
if (arriving) {
el.classList.remove('is-arriving');
void el.offsetWidth;
el.classList.add('is-arriving');
window.setTimeout(function () { el.classList.remove('is-arriving'); }, 1500);
}
});
});
document.querySelectorAll('[data-attention-key]').forEach(function (el) {
if (!present[el.dataset.attentionKey]) el.hidden = true;
});
var any = Object.keys(present).length > 0;
root.hidden = !any;
var overview = document.querySelector('[data-attention-overview]');
if (overview) overview.hidden = !any;
stale(false);
saveSeen();
}
function stale(value) {
root.classList.toggle('is-stale', value);
document.querySelectorAll('[data-attention-health]').forEach(function (el) { el.hidden = !value; });
if (value) root.querySelectorAll('.attention-shortcut').forEach(function (el) { el.classList.add('is-stale'); });
}
function schedule(delay) {
window.clearTimeout(timer);
if (!stopped && !document.hidden) timer = window.setTimeout(refresh, delay || 30000);
}
function refresh() {
if (stopped || busy || document.hidden) return;
if (Date.now() - lastRequest < 3000) { schedule(3000); return; }
busy = true; lastRequest = Date.now();
var controller = new AbortController();
var timeout = window.setTimeout(function () { controller.abort(); }, 10000);
fetch(endpoint, { credentials: 'same-origin', cache: 'no-store', signal: controller.signal,
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } })
.then(function (response) {
if (response.status === 401 || response.status === 403 || response.status === 428 || response.redirected) {
stopped = true;
throw Error('Session unavailable');
}
if (!response.ok) throw Error('Refresh failed');
return response.json();
}).then(function (result) {
if (!result.success || !result.data || !Array.isArray(result.data.items)) throw Error('Invalid summary');
update(result.data);
}).catch(function () { stale(true); })
.finally(function () { window.clearTimeout(timeout); busy = false; schedule(); });
}
try { update(JSON.parse(root.dataset.attentionInitial)); } catch (e) { stale(true); }
document.addEventListener('visibilitychange', function () { window.clearTimeout(timer); if (!document.hidden) refresh(); });
document.addEventListener('adminx:drawer:closed', function () { schedule(1000); });
document.addEventListener('adminx:form-saved', function () { schedule(1000); });
window.addEventListener('pageshow', function (event) { if (event.persisted) refresh(); });
A.Attention = { refresh: refresh };
schedule();
})(window, document);