128 lines
3.8 KiB
JavaScript
128 lines
3.8 KiB
JavaScript
/**
|
|
* 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();
|
|
},
|
|
};
|
|
}
|