/** * Helpdesk ticket detail page — async communication aside. */ import { getJson } from '/js/core/app-http.js'; import { resolveHost } from '/js/core/app-dom.js'; import { renderCommunicationError, renderCommunicationFeed, renderCommunicationHint, } from './helpdesk-communication.js'; const EMPTY_API = Object.freeze({ destroy: () => {} }); const resolveContainer = (root) => { const host = resolveHost(root); if (host instanceof HTMLElement && host.matches('.app-details-container[data-ticket-no]')) { return host; } return host.querySelector('.app-details-container[data-ticket-no]'); }; export function initHelpdeskTicket(root = document) { const container = resolveContainer(root); if (!container) { return EMPTY_API; } const ticketNo = container.dataset.ticketNo || ''; const communicationUrl = container.dataset.ticketCommunicationUrl || ''; const fileDownloadUrl = container.dataset.fileDownloadUrl || ''; if (!ticketNo || !communicationUrl) { return EMPTY_API; } const listenerController = new AbortController(); const requestController = new AbortController(); const on = (target, type, handler, options = {}) => { if (!target || typeof target.addEventListener !== 'function') { return; } target.addEventListener(type, handler, { ...options, signal: listenerController.signal }); }; const i18nEl = document.getElementById('helpdesk-ticket-i18n'); const i18n = i18nEl ? JSON.parse(i18nEl.textContent || '{}') : {}; const t = (key) => i18n[key] || key; const toggleHidden = (id, hidden) => { const el = document.getElementById(id); if (el) { el.hidden = hidden; } }; const loadCommunication = async (refresh = false) => { const feedEl = document.getElementById('ticket-communication-feed'); const loadingEl = document.getElementById('ticket-communication-loading'); const contentEl = document.getElementById('ticket-communication-content'); if (!feedEl || !loadingEl || !contentEl) { return; } contentEl.hidden = true; loadingEl.hidden = false; try { const params = new URLSearchParams({ ticketNo }); if (refresh) { params.set('refresh', '1'); } const data = await getJson(`${communicationUrl}?${params.toString()}`, { signal: requestController.signal, }); toggleHidden('ticket-communication-loading', true); toggleHidden('ticket-communication-content', false); if (!data || data.ok !== true) { feedEl.innerHTML = renderCommunicationError(t('Could not load communication history.')); return; } let html = ''; if ( data.meta && data.meta.soap_used === false && data.meta.fallback_used === true && data.meta.soap_error ) { html += renderCommunicationHint(t('Live communication unavailable, showing activity fallback.')); } html += renderCommunicationFeed(data.entries || [], { t, emptyMessage: 'No communication found.', showTicketNo: false, fileDownloadUrl, }); feedEl.innerHTML = html; } catch (error) { if (error instanceof Error && error.name === 'AbortError') { return; } toggleHidden('ticket-communication-loading', true); toggleHidden('ticket-communication-content', false); const feedEl = document.getElementById('ticket-communication-feed'); if (feedEl) { feedEl.innerHTML = renderCommunicationError(t('Could not load communication history.')); } } }; const refreshButton = container.querySelector('button[name="ticket-refresh"]'); on(refreshButton, 'click', () => { void loadCommunication(true); }); void loadCommunication(); return { destroy: () => { listenerController.abort(); requestController.abort(); }, }; }