/** * Ticket Detail View * Shows full ticket info with quick-edit dropdowns, article timeline, and add-note form. */ const TicketDetailView = { ticketId: null, htmlMode: false, originalValues: {}, noteAttachments: [], saveDraft() { if (!this.ticketId) return; const body = this.noteQuill ? this.noteQuill.root.innerHTML.trim() : ''; const subject = document.getElementById('note-subject') ? document.getElementById('note-subject').value.trim() : ''; const time_unit = document.getElementById('note-time-units') ? document.getElementById('note-time-units').value.trim() : ''; if ((body !== '
Caricamento ticket...
${App.escapeHtml(subject)}
`; if (this.noteQuill) { this.noteQuill.root.innerHTML = body; } } // If subject is empty but body is provided, fill subject with truncated plain text of body if (body && !subject) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = body; const plainText = tempDiv.textContent || tempDiv.innerText || ''; subject = plainText.trim().substring(0, 50) || 'Nota interna'; document.getElementById('note-subject').value = subject; } // If both are still empty, show warning if (!body && !subject) { Toast.warning('Inserisci un oggetto o il corpo della nota prima di inviare'); return; } try { noteSendBtn.disabled = true; noteSendBtn.innerHTML = ' Invio...'; const res = await App.api(`/api/tickets/${this.ticketId}/articles`, { method: 'POST', body: JSON.stringify({ subject, body, time_unit, attachments: this.noteAttachments.length > 0 ? this.noteAttachments : undefined }), }); this.noteAttachments = []; // Clear attachments if (note_create_time && res.article_id) { try { const formattedDate = note_create_time.replace('T', ' '); await App.api(`/api/tickets/articles/${res.article_id}/retrodata-article`, { method: 'POST', body: JSON.stringify({ create_time: formattedDate }) }); Toast.success('Nota aggiunta e retrodatata!'); } catch (retErr) { Toast.warning('Nota aggiunta, ma errore durante la retrodatazione: ' + retErr.message); } } else { Toast.success(res.message || 'Nota aggiunta!'); } App.clearDraft(this.ticketId, 'note'); App.updateDailyTimer(); this.render(this.ticketId); } catch (err) { Toast.error('Errore: ' + err.message); noteSendBtn.disabled = false; noteSendBtn.innerHTML = 'Invia Nota'; } }); // Note Attachments Upload Handlers const noteAttachBtn = document.getElementById('btn-note-add-attachments'); const noteFileInput = document.getElementById('note-attachments'); if (noteAttachBtn && noteFileInput) { noteAttachBtn.addEventListener('click', () => noteFileInput.click()); noteFileInput.addEventListener('change', (e) => { const files = Array.from(e.target.files); for (const file of files) { const reader = new FileReader(); reader.onload = () => { const base64Data = reader.result.split(',')[1]; this.noteAttachments.push({ filename: file.name, content: base64Data, content_type: file.type }); this.updateNoteAttachmentList(); }; reader.readAsDataURL(file); } noteFileInput.value = ''; // Reset input }); } // Email Compose Button const btnEmailCompose = document.getElementById('btn-open-email-compose'); if (btnEmailCompose) { btnEmailCompose.addEventListener('click', () => { if (window.EmailCompose) { const tId = parseInt(btnEmailCompose.dataset.ticketId, 10); const emailDraft = App.getDraft(tId, 'email'); if (emailDraft) { EmailCompose.open({ ...emailDraft.options, draft: emailDraft }); } else { EmailCompose.open({ ticketId: tId, ticketTn: btnEmailCompose.dataset.ticketTn, ticketTitle: btnEmailCompose.dataset.ticketTitle, customerEmail: btnEmailCompose.dataset.customerEmail, }); } } else { Toast.error('Modulo email non disponibile'); } }); } // Article Email Reply Buttons document.querySelectorAll('.btn-email-article').forEach(btn => { btn.addEventListener('click', () => { const articleId = parseInt(btn.dataset.articleId, 10); const article = articles.find(art => art.article_id == articleId); if (!article) return; if (window.EmailCompose) { const hasHtml = (article.a_content_type || '').toLowerCase().includes('html') || article.a_body.includes('') || article.a_body.includes('/>'); let processedQuoted = article.a_body || ''; if (hasHtml) { const articleAttachments = (attachments || []).filter(att => att.article_id === article.article_id); articleAttachments.forEach(att => { if (att.content_id) { const cleanCid = att.content_id.replace(/[<>]/g, '').trim(); if (cleanCid) { const escapedCid = cleanCid.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); const regex = new RegExp(`cid:${escapedCid}>?`, 'gi'); processedQuoted = processedQuoted.replace(regex, `/api/tickets/attachments/${att.id}`); } } if (att.filename) { const escapedFilename = att.filename.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); const regexFilename = new RegExp(`cid:${escapedFilename}>?`, 'gi'); processedQuoted = processedQuoted.replace(regexFilename, `/api/tickets/attachments/${att.id}`); } }); } const quotedBody = hasHtml ? processedQuoted : App.escapeHtml(article.a_body || '').replace(/\n/g, 'Il ${App.formatDateTime(article.create_time)}, ${App.escapeHtml(article.a_from || 'Sistema')} ha scritto:
${quotedBody}