Swap layout: communication feed becomes the primary main content area (full width), ticket metadata moves to aside panel with 2 stacked KPI tiles (Status, Age) and a Stripe-style key-value definition list (Description, Company link, Contact, Category, Support, Debtor No.). Remove activity timeline entirely — communication feed already includes activity fallback when SOAP is unavailable. Add skeleton bubble loading for async communication. Simplify JS from 211 to 89 lines. Remove unused ticketLogUrl data attribute and i18n keys. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
90 lines
2.7 KiB
JavaScript
90 lines
2.7 KiB
JavaScript
/**
|
|
* Helpdesk ticket detail page — async communication aside.
|
|
*
|
|
* Loads the ticket communication feed via fetch and renders
|
|
* it in the aside panel, matching the debitor detail pattern.
|
|
*/
|
|
import {
|
|
renderCommunicationError,
|
|
renderCommunicationFeed,
|
|
renderCommunicationHint,
|
|
} from './helpdesk-communication.js';
|
|
|
|
const container = document.querySelector('.app-details-container[data-ticket-no]');
|
|
if (container) {
|
|
init(container);
|
|
}
|
|
|
|
function init(container) {
|
|
const ticketNo = container.dataset.ticketNo || '';
|
|
const communicationUrl = container.dataset.ticketCommunicationUrl || '';
|
|
|
|
if (!ticketNo || !communicationUrl) return;
|
|
|
|
// i18n
|
|
const i18nEl = document.getElementById('helpdesk-ticket-i18n');
|
|
const i18n = i18nEl ? JSON.parse(i18nEl.textContent) : {};
|
|
const t = (key) => i18n[key] || key;
|
|
|
|
function showLoading(id) {
|
|
const el = document.getElementById(id);
|
|
if (el) el.hidden = false;
|
|
}
|
|
|
|
function hideLoading(id) {
|
|
const el = document.getElementById(id);
|
|
if (el) el.hidden = true;
|
|
}
|
|
|
|
function showContent(id) {
|
|
const el = document.getElementById(id);
|
|
if (el) el.hidden = false;
|
|
}
|
|
|
|
async function loadCommunication() {
|
|
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;
|
|
|
|
showLoading('ticket-communication-loading');
|
|
|
|
try {
|
|
const params = new URLSearchParams({ ticketNo });
|
|
const response = await fetch(communicationUrl + '?' + params.toString(), { credentials: 'same-origin' });
|
|
const data = await response.json();
|
|
|
|
hideLoading('ticket-communication-loading');
|
|
showContent('ticket-communication-content');
|
|
|
|
if (!data.ok) {
|
|
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,
|
|
});
|
|
|
|
feedEl.innerHTML = html;
|
|
} catch {
|
|
hideLoading('ticket-communication-loading');
|
|
showContent('ticket-communication-content');
|
|
feedEl.innerHTML = renderCommunicationError(t('Could not load communication history.'));
|
|
}
|
|
}
|
|
|
|
loadCommunication();
|
|
}
|