Files
breadcrumb-the-shire/modules/helpdesk/web/js/helpdesk-communication.js

129 lines
4.3 KiB
JavaScript

function esc(str) {
const d = document.createElement('div');
d.textContent = String(str ?? '');
return d.innerHTML;
}
function activityActionLabel(typeVariant, type, stateSubtype, t) {
if (typeVariant === 'status') {
const base = t('changed status');
return stateSubtype ? `${base} (${stateSubtype})` : base;
}
if (typeVariant === 'forward') {
return t('Forwarded');
}
if (typeVariant === 'file') {
return t('attached a file');
}
if (type && String(type).trim() !== '') {
return type;
}
return t('logged an activity');
}
function entryTimestamp(entry, t) {
const date = entry.date || '';
const timeRaw = entry.time || '';
const time = timeRaw.length >= 5 ? timeRaw.slice(0, 5) : timeRaw;
if (date && time) return `${date} ${time}`;
if (entry.timestamp_iso) return entry.timestamp_iso;
if (date) return date;
return t('Unknown time');
}
function participantRole(entry) {
const explicitRole = String(entry.actor_role || '').trim().toLowerCase();
if (explicitRole === 'customer' || explicitRole === 'support') {
return explicitRole;
}
const actor = String(entry.actor || '').trim().toLowerCase();
if (actor.startsWith('kt') || actor.includes('kontakt') || actor.includes('contact')) {
return 'customer';
}
return 'support';
}
function ticketHref(baseUrl, ticketNo) {
const base = String(baseUrl || '').trim();
const no = String(ticketNo || '').trim();
if (!base || !no) return '';
return `${base}${encodeURIComponent(no)}`;
}
export function renderCommunicationError(message) {
return `<div class="notice" data-variant="warning" role="alert"><p>${esc(message)}</p></div>`;
}
export function renderCommunicationHint(message) {
return `<p class="helpdesk-comm-hint">${esc(message)}</p>`;
}
export function renderCommunicationFeed(entries, options = {}) {
const {
t = (k) => k,
emptyMessage = 'No communication found.',
showTicketNo = false,
ticketBaseUrl = '',
} = options;
const list = Array.isArray(entries) ? entries : [];
if (list.length === 0) {
return `<div class="app-empty-state app-empty-state-compact">
<p class="app-empty-state-message">${esc(t(emptyMessage))}</p>
</div>`;
}
let html = '<ol class="helpdesk-comm-feed" role="list">';
for (const entry of list) {
const actor = entry.actor || t('Unknown user');
const typeVariant = entry.type_variant || 'other';
const type = entry.type || '';
const stateSubtype = entry.state_subtype || '';
const message = entry.message || '';
const ticketNo = entry.ticket_no || '';
const timeLabel = entryTimestamp(entry, t);
const ticketUrl = ticketHref(ticketBaseUrl, ticketNo);
if (typeVariant === 'message') {
const role = participantRole(entry);
html += `<li class="helpdesk-chat-row helpdesk-chat-row--message helpdesk-chat-row--${esc(role)}" data-variant="${esc(typeVariant)}">`;
html += '<div class="helpdesk-chat-meta-block">';
html += `<strong class="helpdesk-chat-actor">${esc(actor)}</strong>`;
html += '<small class="helpdesk-chat-meta-row">';
if (showTicketNo && ticketNo) {
if (ticketUrl) {
html += `<a class="helpdesk-chat-meta-link" href="${esc(ticketUrl)}">${esc(t('Ticket'))} ${esc(ticketNo)}</a>`;
} else {
html += `<span class="helpdesk-chat-meta-item">${esc(t('Ticket'))} ${esc(ticketNo)}</span>`;
}
}
html += `<span class="helpdesk-chat-meta-item helpdesk-chat-time">${esc(timeLabel)}</span>`;
html += '</small>';
html += '</div>';
html += `<p class="helpdesk-chat-bubble">${esc(message)}</p>`;
html += '</li>';
continue;
}
const activityAction = activityActionLabel(typeVariant, type, stateSubtype, t);
let activityText = `${actor} ${activityAction}`.trim();
if (timeLabel) {
activityText += ` ${t('on')} ${timeLabel}`;
}
if (showTicketNo && ticketNo) {
activityText += ` · ${t('Ticket')} ${ticketNo}`;
}
html += `<li class="helpdesk-chat-row helpdesk-chat-row--activity" data-variant="${esc(typeVariant)}">`;
html += `<div class="helpdesk-chat-activity" data-variant="${esc(typeVariant)}"><span class="helpdesk-chat-activity-pill">${esc(activityText)}</span></div>`;
html += '</li>';
}
html += '</ol>';
return html;
}