Files
deskhub/chrome-erweiterung/views/tasks.js
T
2026-11-01 11:15:09 +00:00

64 lines
4.4 KiB
JavaScript

// Aufgaben: ansehen, abhaken, neue anlegen.
import { h, clear, icon, toast, errText } from '../lib/dom.js';
import { apiCall, parseServerTime } from '../lib/core.js';
import { spinner, showError } from '../lib/ui.js';
const FILTERS = [['my', 'Meine'], ['open', 'Alle offenen'], ['done', 'Erledigt']];
const memory = { filter: 'my' };
const dueText = (s) => { const d = parseServerTime(s); return d ? d.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' }) + ' ' + d.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }) : ''; };
export async function renderTasks(host, ctx) {
const list = h('div');
const chips = h('div', { class: 'chips' });
const form = h('div');
const drawChips = () => chips.replaceChildren(...FILTERS.map(([k, l]) => h('button', { type: 'button', class: `chip${memory.filter === k ? ' on' : ''}`, onclick: () => { memory.filter = k; drawChips(); load(); } }, l)));
async function load() {
clear(list).append(spinner());
try {
const { data } = await apiCall('tasks.php', { query: { filter: memory.filter } });
ctx.taskStaff = data.staffOptions || [];
clear(list);
if (!data.items.length) return list.append(h('div', { class: 'empty' }, memory.filter === 'done' ? 'Keine erledigten Aufgaben.' : 'Keine Aufgaben. Schön!'));
list.append(h('div', { class: 'stack' }, data.items.map((it) => {
const done = it.status === 'done';
const box = h('input', { type: 'checkbox', checked: done, 'aria-label': 'Erledigt', onchange: async () => {
try { await apiCall('tasks.php', { method: 'POST', body: { action: 'update_status', id: it.id, status: box.checked ? 'done' : 'open' } }); toast(box.checked ? 'Erledigt' : 'Wieder geöffnet'); load(); }
catch (e) { box.checked = !box.checked; toast(errText(e), 'err'); }
} });
return h('div', { class: `card task${done ? ' done' : ''}` }, box, h('div', { class: 'grow' },
h('div', { class: 'tt', style: { fontWeight: 650 } }, it.title),
it.description ? h('div', { class: 'muted' }, it.description) : null,
h('div', { class: 'muted', style: { marginTop: '3px' } }, [it.dueAt ? `fällig ${dueText(it.dueAt)}` : null, it.assignedName ? `für ${it.assignedName}` : null].filter(Boolean).join(' · ')),
it.ticketNumber ? h('button', { class: 'btn small', style: { marginTop: '6px' }, onclick: () => ctx.go('ticket', { number: it.ticketNumber }) }, `#${it.ticketNumber}`) : null),
h('button', { class: 'iconbtn', title: 'Aufgabe löschen', onclick: async () => {
if (!confirm('Aufgabe löschen?')) return;
try { await apiCall('tasks.php', { method: 'POST', body: { action: 'delete', id: it.id } }); load(); } catch (e) { toast(errText(e), 'err'); }
} }, icon('x', 16)));
})));
} catch (e) { showError(ctx, list, e); }
}
function drawForm(open) {
if (!open) { form.replaceChildren(h('button', { class: 'btn', onclick: () => drawForm(true) }, icon('plus', 15), 'Neue Aufgabe')); return; }
const title = h('input', { type: 'text', required: true, maxlength: '200', placeholder: 'Was ist zu tun?' });
const due = h('input', { type: 'datetime-local' });
const ticket = h('input', { type: 'text', placeholder: 'Ticketnummer (optional)' });
const who = h('select', {}, h('option', { value: '' }, 'Niemand'), (ctx.taskStaff || []).map((s) => h('option', { value: s.id, selected: s.id === ctx.session.staff?.id ? '' : undefined }, s.name)));
form.replaceChildren(h('form', { class: 'sheet', onsubmit: async (ev) => {
ev.preventDefault();
try {
await apiCall('tasks.php', { method: 'POST', body: { action: 'create', title: title.value.trim(), dueAt: due.value ? due.value.replace('T', ' ') + ':00' : '', ticketNumber: ticket.value.trim(), assignedToId: who.value ? Number(who.value) : null } });
toast('Aufgabe angelegt'); drawForm(false); load();
} catch (e) { toast(errText(e), 'err'); }
} }, h('label', {}, 'Titel', title), h('div', { class: 'row2' }, h('label', {}, 'Fällig', due), h('label', {}, 'Für', who)), h('label', {}, 'Ticket', ticket),
h('div', { class: 'actions' }, h('button', { class: 'btn primary', type: 'submit' }, 'Anlegen'), h('button', { class: 'btn', type: 'button', onclick: () => drawForm(false) }, 'Abbrechen'))));
title.focus();
}
host.append(h('div', { class: 'stack' }, form, chips, list));
drawChips(); drawForm(false); load();
}