Update conversations.php
This commit is contained in:
+94
-17
@@ -797,8 +797,8 @@
|
||||
|
||||
<div class="chat-input" style="position:relative;">
|
||||
<input type="file" id="file-input" accept="image/*,video/*,audio/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx" style="display: none;">
|
||||
<button class="btn" id="attach-btn" title="Opciones">
|
||||
<i class="fas fa-plus"></i>
|
||||
<button class="btn" id="attach-btn" title="Adjuntar">
|
||||
<i class="fas fa-paperclip" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div id="attach-menu" class="attach-menu" style="display:none;">
|
||||
<button class="attach-option" data-action="file">Enviar archivo</button>
|
||||
@@ -817,7 +817,27 @@
|
||||
<div class="quick-replies-wrapper" style="position:relative;">
|
||||
<button id="quick-replies-toggle" class="btn btn-sm btn-outline-secondary" title="Respuestas rápidas" aria-expanded="false">⚡️</button>
|
||||
<div id="quick-replies-panel" class="quick-replies-panel" style="display:none; position:absolute; bottom:48px; left:0; z-index:1200; min-width:220px; max-width:420px;">
|
||||
<!-- Quick replies buttons inserted dynamically -->
|
||||
<div style="padding:6px;">
|
||||
<input id="quick-replies-search" class="form-control form-control-sm" placeholder="Buscar respuestas o plantillas..." autocomplete="off" />
|
||||
</div>
|
||||
<div class="qr-sections" style="max-height:260px; overflow:auto; padding:6px;">
|
||||
<div class="qr-section">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center;">
|
||||
<strong>Respuestas rápidas</strong>
|
||||
<small id="qr-count" class="text-muted">0</small>
|
||||
</div>
|
||||
<div class="qr-list" style="display:flex; gap:6px; flex-wrap:wrap; margin-top:6px;"></div>
|
||||
</div>
|
||||
<hr style="margin:8px 0; border-color:#eee;">
|
||||
<div class="tpl-section">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center;">
|
||||
<strong>Plantillas</strong>
|
||||
<small id="tpl-count" class="text-muted">0</small>
|
||||
</div>
|
||||
<div class="tpl-list" style="display:flex; gap:6px; flex-wrap:wrap; margin-top:6px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-muted" id="qr-empty" style="padding:8px; display:none;">No hay respuestas rápidas ni plantillas que coincidan.</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn" id="mic-btn" title="Grabar audio" style="margin-left:6px; border:1px solid #ddd;">
|
||||
@@ -1234,10 +1254,44 @@
|
||||
const isOpen = qrPanel.style.display === 'block';
|
||||
qrPanel.style.display = isOpen ? 'none' : 'block';
|
||||
qrToggle.setAttribute('aria-expanded', String(!isOpen));
|
||||
// Focus search when panel opens
|
||||
if (!isOpen) {
|
||||
setTimeout(() => {
|
||||
const s = document.getElementById('quick-replies-search');
|
||||
if (s) { s.value = ''; s.focus(); s.dispatchEvent(new Event('input')); }
|
||||
}, 80);
|
||||
}
|
||||
});
|
||||
|
||||
qrPanel.addEventListener('click', (ev) => { ev.stopPropagation(); });
|
||||
document.addEventListener('click', () => { qrPanel.style.display = 'none'; qrToggle.setAttribute('aria-expanded','false'); });
|
||||
|
||||
// Quick replies search/filter behavior
|
||||
const qrSearch = document.getElementById('quick-replies-search');
|
||||
if (qrSearch) {
|
||||
const filterLists = () => {
|
||||
const q = (qrSearch.value || '').trim().toLowerCase();
|
||||
const qrList = qrPanel.querySelector('.qr-list');
|
||||
const tplList = qrPanel.querySelector('.tpl-list');
|
||||
let qrMatches = 0, tplMatches = 0;
|
||||
if (qrList) Array.from(qrList.children).forEach(b => {
|
||||
const t = (b.textContent || '').toLowerCase();
|
||||
const ok = q === '' || t.indexOf(q) !== -1;
|
||||
b.style.display = ok ? 'inline-block' : 'none';
|
||||
if (ok) qrMatches++;
|
||||
});
|
||||
if (tplList) Array.from(tplList.children).forEach(b => {
|
||||
const t = (b.textContent || '').toLowerCase();
|
||||
const ok = q === '' || t.indexOf(q) !== -1;
|
||||
b.style.display = ok ? 'inline-block' : 'none';
|
||||
if (ok) tplMatches++;
|
||||
});
|
||||
const qrCount = document.getElementById('qr-count'); if (qrCount) qrCount.textContent = qrMatches;
|
||||
const tplCount = document.getElementById('tpl-count'); if (tplCount) tplCount.textContent = tplMatches;
|
||||
const empty = document.getElementById('qr-empty'); if (empty) empty.style.display = (qrMatches + tplMatches) ? 'none' : 'block';
|
||||
};
|
||||
qrSearch.addEventListener('input', filterLists);
|
||||
}
|
||||
}
|
||||
|
||||
// Mic / recording
|
||||
@@ -1252,12 +1306,16 @@
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
// Use lexical captured self to avoid 'this' binding issues in event handlers
|
||||
const self = this;
|
||||
|
||||
if (micBtn) {
|
||||
micBtn.addEventListener('click', () => {
|
||||
if (this._mediaRecorder && this._mediaRecorder.state === 'recording') {
|
||||
this.stopRecording();
|
||||
micBtn.addEventListener('click', (ev) => {
|
||||
ev.preventDefault();
|
||||
if (self._mediaRecorder && self._mediaRecorder.state === 'recording') {
|
||||
self.stopRecording();
|
||||
} else {
|
||||
this.startRecording();
|
||||
self.startRecording();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2353,12 +2411,22 @@
|
||||
async loadQuickReplies() {
|
||||
const panel = document.getElementById('quick-replies-panel');
|
||||
if (!panel) return;
|
||||
panel.innerHTML = '';
|
||||
// Clear both lists
|
||||
const qrList = panel.querySelector('.qr-list');
|
||||
const tplList = panel.querySelector('.tpl-list');
|
||||
const qrCount = panel.querySelector('#qr-count');
|
||||
const tplCount = panel.querySelector('#tpl-count');
|
||||
if (qrList) qrList.innerHTML = '';
|
||||
if (tplList) tplList.innerHTML = '';
|
||||
if (qrCount) qrCount.textContent = '0';
|
||||
if (tplCount) tplCount.textContent = '0';
|
||||
|
||||
try {
|
||||
// Load autoresponses (text quick replies)
|
||||
const respText = await apiCall('get_autoresponses.php');
|
||||
if (respText && respText.success && Array.isArray(respText.data)) {
|
||||
respText.data.slice(0,6).forEach(r => {
|
||||
let added = 0;
|
||||
respText.data.forEach(r => {
|
||||
if (!r.is_active) return;
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'btn btn-sm btn-outline-primary';
|
||||
@@ -2372,17 +2440,20 @@
|
||||
panel.style.display = 'none';
|
||||
document.getElementById('quick-replies-toggle').setAttribute('aria-expanded','false');
|
||||
});
|
||||
panel.appendChild(btn);
|
||||
if (qrList) qrList.appendChild(btn);
|
||||
added++;
|
||||
});
|
||||
if (qrCount) qrCount.textContent = String(added);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading quick replies (text)', e);
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await apiCall('get_templates.php?approved_only=1&limit=10');
|
||||
const resp = await apiCall('get_templates.php?approved_only=1&limit=30');
|
||||
if (resp && resp.success && Array.isArray(resp.data)) {
|
||||
resp.data.slice(0,4).forEach(t => {
|
||||
let added = 0;
|
||||
resp.data.forEach(t => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'btn btn-sm btn-outline-secondary';
|
||||
let text = (t.body_text || t.name || t.template_name || '').replace(/\n/g,' ');
|
||||
@@ -2390,8 +2461,10 @@
|
||||
btn.textContent = text.length > 30 ? text.substring(0,30) + '...' : text;
|
||||
btn.title = t.name;
|
||||
btn.addEventListener('click', () => { this.sendTemplateQuick(t.template_name, t.language_code || 'es'); panel.style.display='none'; document.getElementById('quick-replies-toggle').setAttribute('aria-expanded','false'); });
|
||||
panel.appendChild(btn);
|
||||
if (tplList) tplList.appendChild(btn);
|
||||
added++;
|
||||
});
|
||||
if (tplCount) tplCount.textContent = String(added);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading quick replies (templates)', e);
|
||||
@@ -2400,10 +2473,14 @@
|
||||
// Also populate the template select
|
||||
try { await loadTemplatesInto('#templateSelect'); } catch(e){console.warn('Could not load templates into select', e);}
|
||||
|
||||
// Show a small hint if there are no quick replies
|
||||
if (!panel.children.length) {
|
||||
panel.innerHTML = '<div class="text-muted" style="padding:8px; font-size:13px;">No hay respuestas rápidas</div>';
|
||||
}
|
||||
// Show a small hint if there are no quick replies and no templates
|
||||
const empty = panel.querySelector('#qr-empty');
|
||||
const total = (qrList ? qrList.children.length : 0) + (tplList ? tplList.children.length : 0);
|
||||
if (empty) empty.style.display = total ? 'none' : 'block';
|
||||
|
||||
// Trigger an initial filter (useful when search has an active value)
|
||||
const sq = panel.querySelector('#quick-replies-search'); if (sq) sq.dispatchEvent(new Event('input'));
|
||||
|
||||
}
|
||||
|
||||
async sendTemplateQuick(templateName, language) {
|
||||
|
||||
Reference in New Issue
Block a user