// Ticketliste mit Filtern, Suche und „Mehr laden“. import { h, clear, icon } from '../lib/dom.js'; import { apiCall } from '../lib/core.js'; import { spinner, ticketCard, showError } from '../lib/ui.js'; const OPEN = 'open,pending,answered,on_hold'; export const FILTERS = [ ['mine', 'Meine', { assigned: 'me', status: OPEN }], ['unassigned', 'Nicht zugewiesen', { assigned: 'unassigned', status: OPEN }], ['overdue', 'Überfällig', { sla: 'overdue', status: OPEN }], ['open_status', 'Unbeantwortet', { status: 'open' }], ['following', 'Beobachtet', { following: 1, status: OPEN }], ['snoozed', 'Wiedervorlage', { snoozed: 1, status: OPEN }], ['all', 'Alle offenen', { status: OPEN }], ['done', 'Gelöst/Geschlossen', { status: 'resolved,closed' }], ]; const memory = { filter: 'mine', q: '' }; export async function renderTickets(host, ctx, params = {}) { if (params.filter) { memory.filter = params.filter; memory.q = ''; } if (params.q !== undefined) memory.q = params.q; let page = 1; const results = h('div'); const input = h('input', { type: 'search', placeholder: 'Betreff, Nummer, Name, Text …', 'aria-label': 'Suche', maxlength: '100', value: memory.q }); const chips = h('div', { class: 'chips', role: 'group' }); const drawChips = () => chips.replaceChildren(...FILTERS.map(([key, label]) => h('button', { class: `chip${!memory.q && memory.filter === key ? ' on' : ''}`, type: 'button', onclick: () => { memory.filter = key; memory.q = ''; input.value = ''; drawChips(); load(true); } }, label))); async function load(reset) { if (reset) { page = 1; clear(results).append(spinner()); } const base = FILTERS.find((f) => f[0] === memory.filter)?.[2] || {}; const query = memory.q ? { q: memory.q, status: 'open,pending,answered,on_hold,resolved,closed' } : base; try { const { data } = await apiCall('tickets.php', { query: { ...query, page, perPage: 25 } }); if (reset) clear(results); else results.querySelector('.more')?.remove(); if (reset) results.append(h('div', { class: 'muted', style: { margin: '2px 2px 8px' } }, `${data.total} Ticket${data.total === 1 ? '' : 's'}`)); const list = results.querySelector('ul.tickets') || results.appendChild(h('ul', { class: 'tickets' })); if (!data.items.length && reset) { list.remove(); results.append(h('div', { class: 'empty' }, memory.q ? 'Keine Treffer.' : 'Keine Tickets in dieser Ansicht.')); } for (const t of data.items) list.append(ticketCard(t, (x) => ctx.go('ticket', { number: x.number }))); if (data.hasMore) results.append(h('div', { class: 'more actions', style: { justifyContent: 'center', margin: '10px 0' } }, h('button', { class: 'btn', onclick: () => { page += 1; load(false); } }, 'Mehr laden'))); } catch (e) { showError(ctx, results, e); } } host.append(h('div', { class: 'stack' }, h('form', { onsubmit: (ev) => { ev.preventDefault(); const q = input.value.trim(); memory.q = q.length >= 2 ? q : ''; drawChips(); load(true); } }, h('div', { class: 'searchbox' }, icon('search', 16), input)), chips, results)); drawChips(); chips.querySelector('.chip.on')?.scrollIntoView({ inline: 'center', block: 'nearest' }); load(true); }