56 lines
3.6 KiB
JavaScript
56 lines
3.6 KiB
JavaScript
// Start: Begrüßung, eigener Status, Kennzahlen, als Nächstes fällige Tickets.
|
||
import { h, clear, icon, toast, errText } from '../lib/dom.js';
|
||
import { apiCall, AVAILABILITY, openWeb, compareVersions } from '../lib/core.js';
|
||
import { spinner, ticketList, showError, segmented } from '../lib/ui.js';
|
||
|
||
export async function renderHome(host, ctx) {
|
||
host.append(spinner());
|
||
try {
|
||
const [dash, avail] = await Promise.all([
|
||
apiCall('dashboard.php').then((r) => r.data),
|
||
apiCall('availability.php').then((r) => r.data).catch(() => null),
|
||
]);
|
||
clear(host);
|
||
const first = (ctx.session.staff?.name || '').split(' ')[0];
|
||
const stack = h('div', { class: 'stack' });
|
||
stack.append(h('div', {}, h('div', { class: 'muted' }, new Date().toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long' })), h('div', { class: 'hello' }, `Hallo ${first || ''}`.trim())));
|
||
|
||
// Neue Version der Erweiterung: Hinweis mit Weg zum Download (die Seite „Apps“ der Weboberfläche)
|
||
try {
|
||
const { update } = await chrome.storage.local.get('update');
|
||
if (update && compareVersions(update.version, chrome.runtime.getManifest().version) > 0) {
|
||
stack.append(h('div', { class: 'card' }, h('h2', {}, `Update verfügbar: ${update.version}`),
|
||
h('div', { class: 'muted' }, 'Eine neuere Version der Erweiterung liegt bereit. Auf der Seite „Apps“ laden, entpacken und unter chrome://extensions neu laden.'),
|
||
update.notes ? h('div', { class: 'muted', style: { marginTop: '6px', whiteSpace: 'pre-wrap' } }, update.notes) : null,
|
||
h('div', { style: { marginTop: '8px' } }, h('button', { class: 'btn', onclick: () => openWeb('/staff/apps.php').catch((e) => toast(errText(e), 'err')) }, 'Download-Seite öffnen'))));
|
||
}
|
||
} catch { /* ohne Hinweis weiter */ }
|
||
|
||
if (avail) {
|
||
let current = avail.myStatus;
|
||
const holder = h('div');
|
||
const draw = () => holder.replaceChildren(segmented(Object.entries(AVAILABILITY), current, async (v) => {
|
||
const old = current; current = v; draw();
|
||
try { await apiCall('availability.php', { method: 'POST', body: { status: v, note: avail.myNote || '' } }); ctx.setStatusDot(v); toast(`Status: ${AVAILABILITY[v]}`); }
|
||
catch (e) { current = old; draw(); toast(errText(e), 'err'); }
|
||
}));
|
||
draw();
|
||
ctx.setStatusDot(current);
|
||
stack.append(h('div', { class: 'card' }, h('h2', {}, 'Mein Status'), holder));
|
||
}
|
||
|
||
const stat = (value, label, cls, filter) => h('button', { class: `stat ${cls || ''}`, onclick: () => ctx.go('tickets', { filter }) }, h('div', { class: 'v' }, value), h('div', { class: 'k' }, label));
|
||
stack.append(h('div', { class: 'stats' },
|
||
stat(dash.myOpen ?? 0, 'Meine offenen', '', 'mine'),
|
||
stat(dash.overdue ?? 0, 'Überfällig', dash.overdue ? 'warn' : '', 'overdue'),
|
||
stat(dash.unassigned ?? 0, 'Nicht zugewiesen', '', 'unassigned'),
|
||
stat(dash.unanswered ?? 0, 'Unbeantwortet', '', 'open_status')),
|
||
h('div', { class: 'stats' },
|
||
h('div', { class: 'stat good' }, h('div', { class: 'v' }, dash.resolvedToday ?? 0), h('div', { class: 'k' }, 'Heute gelöst')),
|
||
h('div', { class: 'stat' }, h('div', { class: 'v' }, dash.slaPercent == null ? '–' : `${Math.round(dash.slaPercent)} %`), h('div', { class: 'k' }, 'SLA eingehalten (30 Tage)'))));
|
||
|
||
stack.append(h('h2', { class: 'sec', style: { margin: '6px 0 0' } }, 'Als Nächstes fällig'), ticketList(dash.recent || [], (t) => ctx.go('ticket', { number: t.number }), 'Alles erledigt. Nichts offen.'));
|
||
host.append(stack);
|
||
} catch (e) { showError(ctx, host, e); }
|
||
}
|