Files
deskhub/DeskHub-Webseite/assets/js/live-tickets.js
T
2026-10-24 20:14:51 +00:00

104 lines
4.3 KiB
JavaScript

/**
* Live-Anzeige im Mitarbeiterbereich: neue Tickets erscheinen sofort als Hinweis unten rechts, die Zahl steht im Browser-Tab und die
* Kennzahlen auf der Übersicht (Elemente mit data-live-count) aktualisieren sich von selbst. Fragt /staff/live_tickets.php ab.
*/
(function () {
'use strict';
if (window.__deskhubLive) return;
window.__deskhubLive = true;
var KEY = 'deskhub_live_last_ticket';
var since = 0;
try { since = parseInt(sessionStorage.getItem(KEY) || '0', 10) || 0; } catch (e) {}
var unseen = 0;
var baseTitle = document.title;
var stopped = false;
var box = null;
function container() {
if (box) return box;
box = document.createElement('div');
box.setAttribute('aria-live', 'polite');
box.style.cssText = 'position:fixed;right:18px;bottom:18px;z-index:2147483000;display:flex;flex-direction:column;gap:10px;max-width:360px;font:14px/1.4 "Segoe UI",system-ui,sans-serif';
document.body.appendChild(box);
return box;
}
function toast(t) {
var a = document.createElement('a');
a.href = '/staff/ticket_view.php?n=' + encodeURIComponent(t.number);
a.style.cssText = 'display:block;background:#0f172a;color:#fff;text-decoration:none;border-radius:12px;padding:12px 16px;box-shadow:0 10px 30px rgba(0,0,0,.35);border-left:4px solid #2dd4bf;transition:opacity .4s,transform .4s;opacity:0;transform:translateY(10px)';
var h = document.createElement('div');
h.style.cssText = 'font-size:.74rem;letter-spacing:.04em;text-transform:uppercase;color:#5eead4;font-weight:700';
h.textContent = 'Neues Ticket #' + t.number + (t.department ? ' · ' + t.department : '');
var s = document.createElement('div');
s.style.cssText = 'font-weight:600;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
s.textContent = t.subject;
var n = document.createElement('div');
n.style.cssText = 'color:#94a3b8;font-size:.82rem';
n.textContent = t.name;
a.appendChild(h); a.appendChild(s); a.appendChild(n);
container().appendChild(a);
requestAnimationFrame(function () { a.style.opacity = '1'; a.style.transform = 'none'; });
setTimeout(function () { a.style.opacity = '0'; setTimeout(function () { a.remove(); }, 450); }, 14000);
a.addEventListener('click', function () { a.remove(); });
}
function info(text) {
var d = document.createElement('div');
d.style.cssText = 'background:#334155;color:#e2e8f0;border-radius:10px;padding:8px 14px;font-size:.84rem;box-shadow:0 6px 18px rgba(0,0,0,.3)';
d.textContent = text;
container().appendChild(d);
setTimeout(function () { d.remove(); }, 14000);
}
function setCounts(c) {
document.querySelectorAll('[data-live-count]').forEach(function (el) {
var v = c[el.getAttribute('data-live-count')];
if (v === undefined || el.textContent.trim() === String(v)) return;
el.textContent = v;
el.style.transition = 'transform .3s';
el.style.transform = 'scale(1.25)';
setTimeout(function () { el.style.transform = 'none'; }, 350);
});
}
function updateTitle() {
document.title = unseen > 0 ? '(' + unseen + ') ' + baseTitle : baseTitle;
}
function seen() {
if (unseen === 0) return;
unseen = 0;
updateTitle();
}
document.addEventListener('visibilitychange', function () { if (!document.hidden) seen(); });
window.addEventListener('focus', seen);
function poll() {
if (stopped) return;
fetch('/staff/live_tickets.php?since=' + since, { credentials: 'same-origin', cache: 'no-store' })
.then(function (r) {
if (r.status === 401 || r.status === 403) { stopped = true; return null; }
return r.ok ? r.json() : null;
})
.then(function (d) {
if (!d) return;
setCounts(d.counts || {});
var list = d.tickets || [];
list.forEach(toast);
if (d.more > 0) info('… und ' + d.more + ' weitere neue Tickets');
if (list.length) {
unseen += list.length + (d.more || 0);
if (document.hidden || !document.hasFocus()) updateTitle(); else unseen = 0;
}
if (d.latest > since) {
since = d.latest;
try { sessionStorage.setItem(KEY, String(since)); } catch (e) {}
}
})
.catch(function () {})
.then(function () { if (!stopped) setTimeout(poll, document.hidden ? 30000 : 10000); });
}
setTimeout(poll, 1500);
})();