660 lines
26 KiB
JavaScript
660 lines
26 KiB
JavaScript
/**
|
|
* emailCompose.js
|
|
* Modal per la composizione e invio email dal contesto di un ticket.
|
|
* Utilizza Quill.js per l'editor HTML, supporta allegati e immagini inline.
|
|
*/
|
|
|
|
const EmailCompose = (() => {
|
|
let quillEditor = null;
|
|
let attachmentsList = [];
|
|
let currentOptions = {};
|
|
let toTagsCtrl = null;
|
|
let ccTagsCtrl = null;
|
|
let bccTagsCtrl = null;
|
|
|
|
// ── CSS ──────────────────────────────────────────────────────────────────────
|
|
function injectStyles() {
|
|
if (document.getElementById('email-compose-styles')) return;
|
|
const style = document.createElement('style');
|
|
style.id = 'email-compose-styles';
|
|
style.textContent = `
|
|
#email-compose-overlay {
|
|
position: fixed; inset: 0; z-index: 9000;
|
|
background: rgba(0,0,0,0.55);
|
|
backdrop-filter: blur(4px);
|
|
display: flex; align-items: center; justify-content: center;
|
|
animation: fadeIn 0.15s ease;
|
|
}
|
|
@keyframes fadeIn { from { opacity:0 } to { opacity:1 } }
|
|
|
|
#email-compose-modal {
|
|
background: var(--bg-card);
|
|
border: 1px solid var(--border-light);
|
|
border-radius: var(--radius-xl, 14px);
|
|
box-shadow: 0 24px 80px rgba(0,0,0,0.35);
|
|
width: min(860px, 95vw);
|
|
max-height: 92vh;
|
|
display: flex; flex-direction: column;
|
|
animation: slideUp 0.18s ease;
|
|
}
|
|
@keyframes slideUp { from { transform: translateY(20px); opacity:0 } to { transform: translateY(0); opacity:1 } }
|
|
|
|
#email-compose-modal .ec-header {
|
|
padding: 16px 20px 12px;
|
|
border-bottom: 1px solid var(--border-subtle);
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
flex-shrink: 0;
|
|
}
|
|
#email-compose-modal .ec-title {
|
|
font-size: 1rem; font-weight: 600; color: var(--text-primary);
|
|
display: flex; align-items: center; gap: 8px;
|
|
}
|
|
#email-compose-modal .ec-body {
|
|
padding: 16px 20px;
|
|
overflow-y: auto;
|
|
flex: 1;
|
|
display: flex; flex-direction: column; gap: 12px;
|
|
}
|
|
#email-compose-modal .ec-field {
|
|
display: flex; flex-direction: column; gap: 4px;
|
|
}
|
|
#email-compose-modal .ec-label {
|
|
font-size: 0.75rem; font-weight: 600; color: var(--text-secondary);
|
|
text-transform: uppercase; letter-spacing: 0.04em;
|
|
}
|
|
#email-compose-modal .ec-tags-input {
|
|
display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid var(--border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: 6px 10px; min-height: 36px; cursor: text;
|
|
}
|
|
#email-compose-modal .ec-tags-input:focus-within {
|
|
border-color: var(--accent-primary);
|
|
box-shadow: 0 0 0 3px rgba(var(--accent-rgb,99,102,241),0.12);
|
|
}
|
|
#email-compose-modal .ec-tags-input.drag-over {
|
|
border-color: var(--accent-primary);
|
|
background: rgba(99,102,241,0.06);
|
|
}
|
|
#email-compose-modal .ec-tag {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
background: var(--accent-primary); color: #fff;
|
|
border-radius: 4px; padding: 2px 6px; font-size: 0.78rem;
|
|
}
|
|
#email-compose-modal .ec-tag button {
|
|
background: none; border: none; color: rgba(255,255,255,0.8);
|
|
cursor: pointer; padding: 0; line-height: 1; font-size: 0.9rem;
|
|
}
|
|
#email-compose-modal .ec-tag button:hover { color: #fff; }
|
|
#email-compose-modal .ec-tag-input {
|
|
border: none; outline: none; background: transparent;
|
|
font-size: 0.88rem; color: var(--text-primary);
|
|
min-width: 160px; flex: 1;
|
|
}
|
|
#email-compose-modal .ec-editor-wrapper {
|
|
border: 1px solid var(--border-subtle);
|
|
border-radius: var(--radius-md);
|
|
overflow: hidden;
|
|
background: var(--bg-tertiary);
|
|
}
|
|
#email-compose-modal .ec-editor-wrapper .ql-toolbar {
|
|
border: none; border-bottom: 1px solid var(--border-subtle);
|
|
background: var(--bg-secondary);
|
|
}
|
|
#email-compose-modal .ec-editor-wrapper .ql-container {
|
|
border: none; min-height: 220px; font-size: 0.9rem;
|
|
}
|
|
#email-compose-modal .ec-attachments-zone {
|
|
border: 2px dashed var(--border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: 12px 14px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: border-color 0.15s, background 0.15s;
|
|
font-size: 0.82rem; color: var(--text-muted);
|
|
}
|
|
#email-compose-modal .ec-attachments-zone:hover,
|
|
#email-compose-modal .ec-attachments-zone.drag-over {
|
|
border-color: var(--accent-primary);
|
|
background: rgba(var(--accent-rgb,99,102,241),0.06);
|
|
color: var(--text-secondary);
|
|
}
|
|
#email-compose-modal .ec-file-list {
|
|
display: flex; flex-direction: column; gap: 4px;
|
|
}
|
|
#email-compose-modal .ec-file-item {
|
|
display: flex; align-items: center; gap: 8px;
|
|
font-size: 0.82rem; padding: 4px 8px;
|
|
background: var(--bg-secondary); border-radius: var(--radius-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
#email-compose-modal .ec-file-item button {
|
|
margin-left: auto; background: none; border: none; cursor: pointer;
|
|
color: var(--text-muted); font-size: 0.85rem; padding: 0 2px;
|
|
}
|
|
#email-compose-modal .ec-file-item button:hover { color: var(--error); }
|
|
#email-compose-modal .ec-footer {
|
|
padding: 12px 20px;
|
|
border-top: 1px solid var(--border-subtle);
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
flex-shrink: 0; gap: 10px;
|
|
}
|
|
#email-compose-modal select.ec-select {
|
|
background: var(--bg-tertiary);
|
|
border: 1px solid var(--border-subtle);
|
|
border-radius: var(--radius-md);
|
|
padding: 6px 12px; font-size: 0.85rem;
|
|
color: var(--text-primary); min-width: 180px;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
// ── Tag Input Helper ──────────────────────────────────────────────────────────
|
|
function makeTagInput(containerId, initialEmails = [], onFocus = null, controllers = null) {
|
|
const container = document.getElementById(containerId);
|
|
const tags = [...initialEmails];
|
|
|
|
function render() {
|
|
const inputEl = container.querySelector('.ec-tag-input');
|
|
const currentVal = inputEl ? inputEl.value : '';
|
|
container.innerHTML = '';
|
|
tags.forEach((email, idx) => {
|
|
const tagEl = document.createElement('span');
|
|
tagEl.className = 'ec-tag';
|
|
tagEl.draggable = true;
|
|
tagEl.innerHTML = `${App.escapeHtml(email)}<button type="button" data-idx="${idx}">✕</button>`;
|
|
|
|
tagEl.addEventListener('dragstart', (e) => {
|
|
e.dataTransfer.setData('text/plain', email);
|
|
e.dataTransfer.setData('source-container-id', containerId);
|
|
});
|
|
|
|
tagEl.querySelector('button').addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
tags.splice(idx, 1);
|
|
render();
|
|
});
|
|
container.appendChild(tagEl);
|
|
});
|
|
const input = document.createElement('input');
|
|
input.className = 'ec-tag-input';
|
|
input.type = 'text';
|
|
input.placeholder = tags.length ? '' : 'email@esempio.com, premi Invio';
|
|
input.value = currentVal;
|
|
|
|
if (onFocus) {
|
|
input.addEventListener('focus', onFocus);
|
|
}
|
|
|
|
input.addEventListener('keydown', (e) => {
|
|
if ((e.key === 'Enter' || e.key === ',') && input.value.trim()) {
|
|
e.preventDefault();
|
|
const val = input.value.trim().replace(/,$/, '');
|
|
if (val && !tags.includes(val)) tags.push(val);
|
|
input.value = '';
|
|
render();
|
|
} else if (e.key === 'Backspace' && !input.value && tags.length) {
|
|
tags.pop();
|
|
render();
|
|
}
|
|
});
|
|
input.addEventListener('blur', () => {
|
|
if (input.value.trim()) {
|
|
const val = input.value.trim().replace(/,$/, '');
|
|
if (val && !tags.includes(val)) tags.push(val);
|
|
input.value = '';
|
|
render();
|
|
}
|
|
});
|
|
container.appendChild(input);
|
|
container.addEventListener('click', () => input.focus());
|
|
}
|
|
|
|
container.addEventListener('dragover', (e) => {
|
|
e.preventDefault();
|
|
container.classList.add('drag-over');
|
|
});
|
|
|
|
container.addEventListener('dragleave', () => {
|
|
container.classList.remove('drag-over');
|
|
});
|
|
|
|
container.addEventListener('drop', (e) => {
|
|
e.preventDefault();
|
|
container.classList.remove('drag-over');
|
|
const email = e.dataTransfer.getData('text/plain');
|
|
const sourceContainerId = e.dataTransfer.getData('source-container-id');
|
|
if (email && sourceContainerId && sourceContainerId !== containerId && controllers) {
|
|
const sourceCtrl = controllers[sourceContainerId];
|
|
if (sourceCtrl) {
|
|
sourceCtrl.removeTag(email);
|
|
ctrl.addTag(email);
|
|
}
|
|
}
|
|
});
|
|
|
|
render();
|
|
|
|
const ctrl = {
|
|
getTags: () => [...tags],
|
|
addTag: (email) => {
|
|
if (!tags.includes(email)) {
|
|
tags.push(email);
|
|
render();
|
|
}
|
|
},
|
|
removeTag: (email) => {
|
|
const idx = tags.indexOf(email);
|
|
if (idx > -1) {
|
|
tags.splice(idx, 1);
|
|
render();
|
|
}
|
|
}
|
|
};
|
|
return ctrl;
|
|
}
|
|
|
|
// ── Build Modal HTML ──────────────────────────────────────────────────────────
|
|
function buildModal() {
|
|
const overlay = document.createElement('div');
|
|
overlay.id = 'email-compose-overlay';
|
|
overlay.innerHTML = `
|
|
<div id="email-compose-modal">
|
|
<div class="ec-header">
|
|
<div class="ec-title">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:18px;height:18px;">
|
|
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
|
<polyline points="22,6 12,13 2,6"/>
|
|
</svg>
|
|
Invia Email
|
|
</div>
|
|
<button id="ec-close" style="background:none;border:none;cursor:pointer;color:var(--text-muted);padding:4px;font-size:1.2rem;" title="Chiudi">✕</button>
|
|
</div>
|
|
<div class="ec-body">
|
|
<div class="ec-field">
|
|
<label class="ec-label">A (To)</label>
|
|
<div class="ec-tags-input" id="ec-to-container"></div>
|
|
</div>
|
|
<div class="ec-field">
|
|
<label class="ec-label">CC</label>
|
|
<div class="ec-tags-input" id="ec-cc-container"></div>
|
|
</div>
|
|
<div class="ec-field">
|
|
<label class="ec-label">BCC (CCN)</label>
|
|
<div class="ec-tags-input" id="ec-bcc-container"></div>
|
|
</div>
|
|
<div class="ec-field">
|
|
<label class="ec-label">Oggetto</label>
|
|
<input type="text" id="ec-subject" class="form-input" style="margin-bottom:0;" placeholder="Oggetto email" />
|
|
</div>
|
|
<div style="display:flex; gap:16px;">
|
|
<div class="ec-field" style="flex:1;">
|
|
<label class="ec-label">Firma</label>
|
|
<select id="ec-signature-select" class="ec-select" style="width:100%; min-width:unset;">
|
|
<option value="">— Nessuna firma —</option>
|
|
</select>
|
|
</div>
|
|
<div class="ec-field" style="flex:1;">
|
|
<label class="ec-label">Gruppi di Indirizzi</label>
|
|
<select id="ec-groups-select" class="ec-select" style="width:100%; min-width:unset;">
|
|
<option value="">— Inserisci gruppo... —</option>
|
|
</select>
|
|
</div>
|
|
<div class="ec-field" style="flex:1;">
|
|
<label class="ec-label">Helpdesk BCC (genera nuovo ticket)</label>
|
|
<select id="ec-helpdesk-cc-select" class="ec-select" style="width:100%; min-width:unset;">
|
|
<option value="0">No (BCC automatico)</option>
|
|
<option value="1">Sì</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="ec-field">
|
|
<label class="ec-label">Corpo</label>
|
|
<div class="ec-editor-wrapper">
|
|
<div id="ec-quill-editor"></div>
|
|
</div>
|
|
</div>
|
|
<div class="ec-field">
|
|
<label class="ec-label">Allegati</label>
|
|
<div class="ec-attachments-zone" id="ec-drop-zone">
|
|
📎 Trascina file qui o clicca per selezionare
|
|
</div>
|
|
<input type="file" id="ec-file-input" multiple style="display:none;" />
|
|
<div class="ec-file-list" id="ec-file-list"></div>
|
|
</div>
|
|
</div>
|
|
<div class="ec-footer">
|
|
<button class="btn btn-ghost btn-sm" id="ec-cancel">Annulla</button>
|
|
<button class="btn btn-primary btn-sm" id="ec-send" style="display:flex;align-items:center;gap:6px;">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;">
|
|
<path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/>
|
|
</svg>
|
|
Invia
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
return overlay;
|
|
}
|
|
|
|
// ── File List Renderer ────────────────────────────────────────────────────────
|
|
function renderFileList() {
|
|
const list = document.getElementById('ec-file-list');
|
|
if (!list) return;
|
|
list.innerHTML = attachmentsList.map((f, idx) => `
|
|
<div class="ec-file-item">
|
|
📎 <strong>${App.escapeHtml(f.filename)}</strong>
|
|
<span style="color:var(--text-muted);font-size:0.75rem;">(${Math.round(f.content.length * 0.75 / 1024)} KB)</span>
|
|
<button data-idx="${idx}" title="Rimuovi">✕</button>
|
|
</div>
|
|
`).join('');
|
|
list.querySelectorAll('button[data-idx]').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
attachmentsList.splice(parseInt(btn.dataset.idx, 10), 1);
|
|
renderFileList();
|
|
});
|
|
});
|
|
}
|
|
|
|
// ── Load Signatures ───────────────────────────────────────────────────────────
|
|
async function loadSignatures(agentId, selectEl) {
|
|
try {
|
|
const sigs = await App.api(`/api/email/signatures?agent_id=${agentId}`);
|
|
selectEl.innerHTML = '<option value="">— Nessuna firma —</option>';
|
|
sigs.forEach(sig => {
|
|
const opt = document.createElement('option');
|
|
opt.value = sig.id;
|
|
opt.textContent = sig.name + (sig.is_default ? ' ★' : '');
|
|
opt.dataset.html = sig.body_html;
|
|
selectEl.appendChild(opt);
|
|
});
|
|
// Pre-select default
|
|
const defSig = sigs.find(s => s.is_default);
|
|
if (defSig) {
|
|
selectEl.value = defSig.id;
|
|
return defSig.body_html;
|
|
}
|
|
} catch (e) { console.warn('[EmailCompose] Signatures load error:', e); }
|
|
return '';
|
|
}
|
|
|
|
// ── Load Address Groups ────────────────────────────────────────────────────────
|
|
async function loadAddressGroups(agentId, selectEl) {
|
|
try {
|
|
const groups = await App.api(`/api/email/address-groups?agent_id=${agentId}`);
|
|
selectEl.innerHTML = '<option value="">— Inserisci gruppo... —</option>';
|
|
groups.forEach(g => {
|
|
const opt = document.createElement('option');
|
|
opt.value = g.id;
|
|
opt.textContent = g.name;
|
|
opt.dataset.emails = g.emails;
|
|
selectEl.appendChild(opt);
|
|
});
|
|
} catch (e) {
|
|
console.warn('[EmailCompose] Address groups load error:', e);
|
|
}
|
|
}
|
|
|
|
// ── Open ─────────────────────────────────────────────────────────────────────
|
|
async function open(options = {}) {
|
|
injectStyles();
|
|
attachmentsList = [];
|
|
currentOptions = options;
|
|
|
|
// Remove existing
|
|
const existing = document.getElementById('email-compose-overlay');
|
|
if (existing) existing.remove();
|
|
|
|
const overlay = buildModal();
|
|
document.body.appendChild(overlay);
|
|
|
|
// Init tag inputs with focus tracking
|
|
const draft = options.draft;
|
|
const initialTo = draft ? draft.to : (options.initialTo || (options.customerEmail ? [options.customerEmail] : []));
|
|
const initialCc = draft ? draft.cc : (options.initialCc || []);
|
|
const initialBcc = draft ? draft.bcc : [];
|
|
|
|
let lastFocusedCtrl = null;
|
|
const controllers = {};
|
|
toTagsCtrl = makeTagInput('ec-to-container', initialTo, () => { lastFocusedCtrl = toTagsCtrl; }, controllers);
|
|
ccTagsCtrl = makeTagInput('ec-cc-container', initialCc, () => { lastFocusedCtrl = ccTagsCtrl; }, controllers);
|
|
bccTagsCtrl = makeTagInput('ec-bcc-container', initialBcc, () => { lastFocusedCtrl = bccTagsCtrl; }, controllers);
|
|
controllers['ec-to-container'] = toTagsCtrl;
|
|
controllers['ec-cc-container'] = ccTagsCtrl;
|
|
controllers['ec-bcc-container'] = bccTagsCtrl;
|
|
lastFocusedCtrl = toTagsCtrl;
|
|
|
|
// Subject
|
|
const subjectEl = document.getElementById('ec-subject');
|
|
if (draft) {
|
|
subjectEl.value = draft.subject || '';
|
|
} else {
|
|
const tn = options.ticketTn || '';
|
|
const title = options.ticketTitle || '';
|
|
subjectEl.value = tn ? `Re: [Ticket#${tn}] ${title}` : title;
|
|
}
|
|
|
|
// Signature and groups select
|
|
const sigSelect = document.getElementById('ec-signature-select');
|
|
const groupsSelect = document.getElementById('ec-groups-select');
|
|
const agentId = App.currentAgentId || 0;
|
|
const defaultSigHtml = await loadSignatures(agentId, sigSelect);
|
|
await loadAddressGroups(agentId, groupsSelect);
|
|
|
|
if (draft) {
|
|
sigSelect.value = draft.signature || '';
|
|
document.getElementById('ec-helpdesk-cc-select').value = draft.helpdeskCc || '0';
|
|
}
|
|
|
|
groupsSelect.addEventListener('change', () => {
|
|
const selectedOpt = groupsSelect.options[groupsSelect.selectedIndex];
|
|
if (!selectedOpt || !selectedOpt.value) return;
|
|
|
|
const emailsStr = selectedOpt.dataset.emails || '';
|
|
const emails = emailsStr.split(',').map(e => e.trim()).filter(Boolean);
|
|
|
|
if (lastFocusedCtrl) {
|
|
emails.forEach(email => {
|
|
lastFocusedCtrl.addTag(email);
|
|
});
|
|
}
|
|
groupsSelect.value = '';
|
|
});
|
|
|
|
// Quill editor
|
|
quillEditor = new Quill('#ec-quill-editor', {
|
|
theme: 'snow',
|
|
placeholder: 'Scrivi il testo della email...',
|
|
modules: {
|
|
toolbar: [
|
|
['bold', 'italic', 'underline', 'strike'],
|
|
[{ 'header': [1, 2, 3, false] }],
|
|
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
|
['link', 'image'],
|
|
[{ 'color': [] }, { 'background': [] }],
|
|
['clean']
|
|
],
|
|
}
|
|
});
|
|
|
|
// Insert initial body and signature
|
|
let initialHtml = '';
|
|
if (draft) {
|
|
if (draft.body) {
|
|
initialHtml = draft.body;
|
|
}
|
|
attachmentsList = draft.attachments || [];
|
|
renderFileList();
|
|
} else {
|
|
if (options.initialBodyHtml) {
|
|
initialHtml += options.initialBodyHtml;
|
|
} else {
|
|
initialHtml += '<p><br></p>';
|
|
}
|
|
if (defaultSigHtml) {
|
|
initialHtml += '<!-- sig -->' + defaultSigHtml;
|
|
}
|
|
}
|
|
quillEditor.clipboard.dangerouslyPasteHTML(initialHtml);
|
|
quillEditor.setSelection(0, 0);
|
|
|
|
// Signature change
|
|
sigSelect.addEventListener('change', () => {
|
|
const selectedOpt = sigSelect.options[sigSelect.selectedIndex];
|
|
const sigHtml = selectedOpt ? (selectedOpt.dataset.html || '') : '';
|
|
// Replace signature: get current body, strip old signature (after first <br>), append new
|
|
const currentHtml = quillEditor.root.innerHTML;
|
|
const sigMarker = '<!-- sig -->';
|
|
const baseHtml = currentHtml.includes(sigMarker)
|
|
? currentHtml.split(sigMarker)[0]
|
|
: currentHtml;
|
|
const newHtml = baseHtml + (sigHtml ? sigMarker + sigHtml : '');
|
|
quillEditor.clipboard.dangerouslyPasteHTML(newHtml);
|
|
});
|
|
|
|
// File drag & drop
|
|
const dropZone = document.getElementById('ec-drop-zone');
|
|
const fileInput = document.getElementById('ec-file-input');
|
|
|
|
dropZone.addEventListener('click', () => fileInput.click());
|
|
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('drag-over'); });
|
|
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over'));
|
|
dropZone.addEventListener('drop', (e) => {
|
|
e.preventDefault(); dropZone.classList.remove('drag-over');
|
|
processFiles(Array.from(e.dataTransfer.files));
|
|
});
|
|
fileInput.addEventListener('change', (e) => {
|
|
processFiles(Array.from(e.target.files));
|
|
fileInput.value = '';
|
|
});
|
|
|
|
// Close handlers
|
|
document.getElementById('ec-close').addEventListener('click', close);
|
|
document.getElementById('ec-cancel').addEventListener('click', close);
|
|
overlay.addEventListener('click', (e) => {
|
|
if (e.target === overlay) {
|
|
saveDraft();
|
|
const ov = document.getElementById('email-compose-overlay');
|
|
if (ov) ov.remove();
|
|
if (quillEditor) { quillEditor = null; }
|
|
attachmentsList = [];
|
|
}
|
|
});
|
|
|
|
// Send
|
|
document.getElementById('ec-send').addEventListener('click', () => sendEmail(toTagsCtrl, ccTagsCtrl, bccTagsCtrl));
|
|
}
|
|
|
|
function processFiles(files) {
|
|
for (const file of files) {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
const base64 = reader.result.split(',')[1];
|
|
attachmentsList.push({ filename: file.name, content: base64, contentType: file.type });
|
|
renderFileList();
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
}
|
|
|
|
// ── Send ─────────────────────────────────────────────────────────────────────
|
|
async function sendEmail(toCtrl, ccCtrl, bccCtrl) {
|
|
const to = toCtrl.getTags();
|
|
const cc = ccCtrl.getTags();
|
|
const bcc = bccCtrl.getTags();
|
|
const subject = document.getElementById('ec-subject').value.trim();
|
|
const bodyHtml = quillEditor ? quillEditor.root.innerHTML : '';
|
|
|
|
if (!to.length) { Toast.warning('Inserisci almeno un destinatario (campo A)'); return; }
|
|
if (!subject) { Toast.warning('Inserisci l\'oggetto della email'); return; }
|
|
|
|
const sendBtn = document.getElementById('ec-send');
|
|
sendBtn.disabled = true;
|
|
sendBtn.innerHTML = '<div class="spinner" style="width:14px;height:14px;border-width:2px;"></div> Invio...';
|
|
|
|
try {
|
|
const agentId = App.currentAgentId || 0;
|
|
const payload = {
|
|
ticketId: currentOptions.ticketId,
|
|
to, cc, bcc, subject, bodyHtml,
|
|
attachments: attachmentsList,
|
|
agentId,
|
|
keepHelpdeskCopy: document.getElementById('ec-helpdesk-cc-select').value === '1',
|
|
inReplyTo: currentOptions.inReplyTo,
|
|
references: currentOptions.references,
|
|
};
|
|
|
|
const res = await App.api('/api/email/send', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload),
|
|
});
|
|
|
|
Toast.success(`Email inviata a ${to.join(', ')}`);
|
|
App.clearDraft(currentOptions.ticketId, 'email');
|
|
close();
|
|
} catch (err) {
|
|
Toast.error('Errore invio email: ' + err.message);
|
|
sendBtn.disabled = false;
|
|
sendBtn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px;"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/></svg> Invia';
|
|
}
|
|
}
|
|
|
|
// ── Close ─────────────────────────────────────────────────────────────────────
|
|
function close() {
|
|
if (currentOptions.ticketId) {
|
|
App.clearDraft(currentOptions.ticketId, 'email');
|
|
}
|
|
const btn = document.getElementById('btn-open-email-compose');
|
|
if (btn) {
|
|
const svg = btn.querySelector('svg');
|
|
btn.innerHTML = '';
|
|
if (svg) btn.appendChild(svg);
|
|
btn.appendChild(document.createTextNode(' Invia Email'));
|
|
}
|
|
const overlay = document.getElementById('email-compose-overlay');
|
|
if (overlay) overlay.remove();
|
|
if (quillEditor) { quillEditor = null; }
|
|
attachmentsList = [];
|
|
}
|
|
|
|
function saveDraft() {
|
|
const overlay = document.getElementById('email-compose-overlay');
|
|
if (!overlay || !currentOptions.ticketId) return;
|
|
|
|
const to = toTagsCtrl ? toTagsCtrl.getTags() : [];
|
|
const cc = ccTagsCtrl ? ccTagsCtrl.getTags() : [];
|
|
const bcc = bccTagsCtrl ? bccTagsCtrl.getTags() : [];
|
|
const subject = document.getElementById('ec-subject') ? document.getElementById('ec-subject').value.trim() : '';
|
|
const body = quillEditor ? quillEditor.root.innerHTML.trim() : '';
|
|
const signature = document.getElementById('ec-signature-select') ? document.getElementById('ec-signature-select').value : '';
|
|
const helpdeskCc = document.getElementById('ec-helpdesk-cc-select') ? document.getElementById('ec-helpdesk-cc-select').value : '0';
|
|
|
|
App.saveDraft(currentOptions.ticketId, {
|
|
type: 'email',
|
|
to,
|
|
cc,
|
|
bcc,
|
|
subject,
|
|
body,
|
|
signature,
|
|
helpdeskCc,
|
|
attachments: [...attachmentsList],
|
|
options: currentOptions
|
|
});
|
|
|
|
const btn = document.getElementById('btn-open-email-compose');
|
|
if (btn) {
|
|
const svg = btn.querySelector('svg');
|
|
btn.innerHTML = '';
|
|
if (svg) btn.appendChild(svg);
|
|
btn.appendChild(document.createTextNode(' Continua mail'));
|
|
}
|
|
App.renderTabs();
|
|
}
|
|
|
|
return { open, close, saveDraft };
|
|
})();
|
|
window.EmailCompose = EmailCompose;
|