').html(html);
messages.push({
index: index,
content: $temp.text().trim()
});
});
// Send translation request
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'mxchat_translate_messages',
session_id: currentSessionId,
target_lang: targetLang,
messages: JSON.stringify(messages),
security: mxchatAdmin.translate_nonce || ''
},
success: function(response) {
if (response.success && response.translations) {
currentTranslationLang = response.language;
applyTranslations(response.translations);
$btn.find('.mxch-translate-text').text('Translate');
} else {
alert(response.error || 'Translation failed. Please try again.');
$btn.find('.mxch-translate-text').text('Translate');
}
},
error: function() {
alert('Translation request failed. Please try again.');
$btn.find('.mxch-translate-text').text('Translate');
},
complete: function() {
$btn.prop('disabled', false);
$btn.find('svg').removeClass('mxch-translate-spinner');
}
});
});
// Show original button click handler
$('#mxch-show-original-btn').on('click', function() {
if (!originalMessages) return;
// Restore original messages
$('#mxch-messages-area .mxch-message-bubble').each(function(index) {
if (originalMessages[index]) {
$(this).html(originalMessages[index]);
$(this).removeClass('translated');
}
});
isTranslated = false;
$(this).hide();
});
// Reset translation state (called when selecting new chat)
function resetTranslationState() {
originalMessages = null;
isTranslated = false;
currentTranslationLang = null;
$('#mxch-show-original-btn').hide();
}
// Make functions available to selectChat
window.resetTranslationState = resetTranslationState;
window.loadSavedTranslation = loadSavedTranslation;
// ==========================================================================
// RAG Context Modal (Sources & Actions Tabs)
// ==========================================================================
function openRagContextModal(messageId) {
const $modal = $('#mxch-rag-modal');
const $loading = $modal.find('.mxch-rag-loading');
const $sourcesContent = $modal.find('.mxch-rag-content');
const $actionsContent = $modal.find('.mxch-actions-content');
// Reset to Sources tab
$modal.find('.mxch-context-tab').removeClass('active');
$modal.find('.mxch-context-tab[data-tab="sources"]').addClass('active');
$('#mxch-tab-sources').show();
$('#mxch-tab-actions').hide();
// Reset badge counts
$('#mxch-sources-count, #mxch-actions-count').hide().text('0');
$modal.fadeIn(200);
$loading.show();
$sourcesContent.html('');
$actionsContent.html('');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'mxchat_get_rag_context',
message_id: messageId
},
success: function(response) {
$loading.hide();
if (response.success && response.data) {
// Render sources tab
renderRagContext(response.data, $sourcesContent);
// Render actions tab
renderActionsContext(response.data, $actionsContent);
// Update badge counts
const sourcesCount = response.data.top_matches ? response.data.top_matches.length : 0;
const actionsCount = response.data.action_analysis ? response.data.action_analysis.length : 0;
if (sourcesCount > 0) {
$('#mxch-sources-count').text(sourcesCount).show();
}
if (actionsCount > 0) {
$('#mxch-actions-count').text(actionsCount).show();
}
} else {
$sourcesContent.html('
Unable to load document context.
');
$actionsContent.html('
No action data available.
');
}
},
error: function() {
$loading.hide();
$sourcesContent.html('
Error loading context. Please try again.
');
$actionsContent.html('
Error loading context. Please try again.
');
}
});
}
// Tab switching
$(document).on('click', '.mxch-context-tab', function() {
const $tab = $(this);
const tabName = $tab.data('tab');
// Update active tab
$('.mxch-context-tab').removeClass('active');
$tab.addClass('active');
// Show/hide content
$('.mxch-tab-content').hide();
$('#mxch-tab-' + tabName).show();
});
function renderRagContext(data, $container) {
let html = '';
// Check if we have any source data
if (!data.top_matches || data.top_matches.length === 0) {
html += '
No document matches found for this response.
';
$container.html(html);
return;
}
html += '
';
html += '
Knowledge Base: ' + escapeHtml(data.knowledge_base_type || 'WordPress Database') + '
';
html += '
Similarity Threshold: ' + Math.round((data.similarity_threshold || 0.35) * 100) + '%
';
html += '
Documents Checked: ' + (data.total_documents_checked || 0) + '
';
html += '
';
const groupedByUrl = {};
data.top_matches.forEach(function(match) {
const url = match.source_display || 'Unknown';
if (!groupedByUrl[url]) {
groupedByUrl[url] = {
url: url,
isUrl: url.startsWith('http'),
bestScore: 0,
usedForContext: false,
matchedChunks: []
};
}
if (match.similarity_percentage > groupedByUrl[url].bestScore) {
groupedByUrl[url].bestScore = match.similarity_percentage;
}
if (match.used_for_context) {
groupedByUrl[url].usedForContext = true;
}
groupedByUrl[url].matchedChunks.push({
chunkIndex: match.chunk_index,
score: match.similarity_percentage,
usedForContext: match.used_for_context
});
});
const urlGroups = Object.values(groupedByUrl).sort((a, b) => b.bestScore - a.bestScore);
const usedUrlCount = data.sources_used > 0 ? data.sources_used : urlGroups.filter(g => g.usedForContext).length;
const chunksInfo = data.total_chunks_used > 0 ? data.total_chunks_used + ' chunks sent to AI' : '';
html += '
';
html += '
Retrieved Documents
';
html += '
' + usedUrlCount + ' source' + (usedUrlCount === 1 ? '' : 's') + ' used for response' + (chunksInfo ? ' · ' + chunksInfo : '') + '
';
urlGroups.forEach(function(group) {
const cardClass = group.usedForContext ? 'mxch-rag-match-used' : 'mxch-rag-match-below';
const statusIcon = group.usedForContext ? '✓' : '✗';
const statusLabel = group.usedForContext ? 'Used' : 'Not Used';
html += '
';
html += '';
html += '
';
html += '
';
});
html += '
';
$container.html(html);
}
function renderActionsContext(data, $container) {
let html = '';
// Check if we have action analysis data
if (!data.action_analysis || data.action_analysis.length === 0) {
html += '
No action analysis available for this message.
Actions are only evaluated when enabled in your bot configuration.
';
$container.html(html);
return;
}
const actions = data.action_analysis;
const triggeredAction = actions.find(a => a.triggered);
const actionsAboveThreshold = actions.filter(a => a.above_threshold).length;
// Summary section
html += '
';
html += '
Actions Evaluated: ' + actions.length + '
';
html += '
Above Threshold: ' + actionsAboveThreshold + '
';
if (triggeredAction) {
html += '
Triggered: ' + escapeHtml(triggeredAction.intent_label) + '
';
}
html += '
';
// Actions list
html += '
';
html += '
Action Scores
';
html += '
Showing all evaluated actions sorted by similarity score
';
actions.forEach(function(action) {
let cardClass = 'mxch-rag-match-below';
let statusIcon = '✗';
let statusLabel = 'Below Threshold';
if (action.triggered) {
cardClass = 'mxch-action-triggered';
statusIcon = '⚡';
statusLabel = 'Triggered';
} else if (action.above_threshold) {
cardClass = 'mxch-rag-match-used';
statusIcon = '✓';
statusLabel = 'Above Threshold';
}
html += '
';
html += '';
html += '
';
html += '
' + escapeHtml(action.intent_label) + '
';
html += '
Callback: ' + escapeHtml(action.callback_function) + '
';
html += '
';
// Score bar visualization
const scoreBarWidth = Math.min(action.similarity_percentage, 100);
const thresholdPos = Math.min(action.threshold_percentage, 100);
html += '
';
html += '
';
html += '
';
html += '
';
html += '
';
});
html += '
';
$container.html(html);
}
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// Close RAG modal
$('.mxch-modal-close').on('click', function() {
$(this).closest('.mxch-modal-overlay').fadeOut(200);
});
$('.mxch-modal-overlay').on('click', function(e) {
if ($(e.target).is('.mxch-modal-overlay')) {
$(this).fadeOut(200);
}
});
$(document).on('keydown', function(e) {
if (e.key === 'Escape') {
$('.mxch-modal-overlay').fadeOut(200);
}
});
// ==========================================================================
// Activity Chart
// ==========================================================================
// Simple chart implementation (no external dependencies)
class SimpleChart {
constructor(canvas, config) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.config = config;
this.padding = { top: 20, right: 20, bottom: 40, left: 50 };
this.render();
}
destroy() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
render() {
const dpr = window.devicePixelRatio || 1;
const rect = this.canvas.getBoundingClientRect();
this.canvas.width = rect.width * dpr;
this.canvas.height = rect.height * dpr;
this.ctx.scale(dpr, dpr);
this.canvas.style.width = rect.width + 'px';
this.canvas.style.height = rect.height + 'px';
const width = rect.width - this.padding.left - this.padding.right;
const height = rect.height - this.padding.top - this.padding.bottom;
// Find max value
let maxValue = 0;
this.config.datasets.forEach(dataset => {
const max = Math.max(...dataset.data);
if (max > maxValue) maxValue = max;
});
// Add some padding to max value
maxValue = Math.ceil(maxValue * 1.1);
if (maxValue === 0) maxValue = 10;
// Draw grid lines
this.ctx.strokeStyle = '#e5e7eb';
this.ctx.lineWidth = 1;
const gridLines = 5;
for (let i = 0; i <= gridLines; i++) {
const y = this.padding.top + (height / gridLines) * i;
this.ctx.beginPath();
this.ctx.moveTo(this.padding.left, y);
this.ctx.lineTo(this.padding.left + width, y);
this.ctx.stroke();
// Draw y-axis labels
const value = maxValue - (maxValue / gridLines) * i;
this.ctx.fillStyle = '#6b7280';
this.ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
this.ctx.textAlign = 'right';
this.ctx.fillText(Math.round(value), this.padding.left - 10, y + 4);
}
// Draw datasets
this.config.datasets.forEach(dataset => {
const points = [];
const xStep = width / (this.config.labels.length - 1 || 1);
dataset.data.forEach((value, index) => {
const x = this.padding.left + (xStep * index);
const y = this.padding.top + height - (value / maxValue * height);
points.push({ x, y, value });
});
// Draw filled area
if (dataset.fill && dataset.backgroundColor) {
this.ctx.fillStyle = dataset.backgroundColor;
this.ctx.beginPath();
this.ctx.moveTo(points[0].x, this.padding.top + height);
points.forEach(point => {
this.ctx.lineTo(point.x, point.y);
});
this.ctx.lineTo(points[points.length - 1].x, this.padding.top + height);
this.ctx.closePath();
this.ctx.fill();
}
// Draw line
this.ctx.strokeStyle = dataset.borderColor;
this.ctx.lineWidth = 3;
this.ctx.lineCap = 'round';
this.ctx.lineJoin = 'round';
this.ctx.beginPath();
points.forEach((point, index) => {
if (index === 0) {
this.ctx.moveTo(point.x, point.y);
} else {
this.ctx.lineTo(point.x, point.y);
}
});
this.ctx.stroke();
// Draw points
points.forEach(point => {
this.ctx.fillStyle = '#ffffff';
this.ctx.beginPath();
this.ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.strokeStyle = dataset.borderColor;
this.ctx.lineWidth = 2;
this.ctx.stroke();
});
});
// Draw x-axis labels
const xStep = width / (this.config.labels.length - 1 || 1);
this.ctx.fillStyle = '#6b7280';
this.ctx.font = '12px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
this.ctx.textAlign = 'center';
this.config.labels.forEach((label, index) => {
const x = this.padding.left + (xStep * index);
this.ctx.fillText(label, x, this.padding.top + height + 20);
});
}
}
// Initialize activity chart
function initActivityChart() {
console.log('[MxChat Chart] initActivityChart called');
const canvas = document.getElementById('mxchat-activity-chart');
console.log('[MxChat Chart] Canvas element:', canvas);
if (!canvas) {
console.log('[MxChat Chart] Canvas not found, aborting');
return;
}
console.log('[MxChat Chart] mxchatChartData exists:', typeof mxchatChartData !== 'undefined');
if (typeof mxchatChartData === 'undefined') {
console.log('[MxChat Chart] mxchatChartData is undefined, aborting');
return;
}
console.log('[MxChat Chart] Raw mxchatChartData:', mxchatChartData);
// Check if chart already exists and destroy it
if (canvas.chartInstance) {
canvas.chartInstance.destroy();
}
const ctx = canvas.getContext('2d');
console.log('[MxChat Chart] Canvas context:', ctx);
console.log('[MxChat Chart] Canvas dimensions:', canvas.getBoundingClientRect());
// Create gradient for chats line
const chatsGradient = ctx.createLinearGradient(0, 0, 0, 300);
chatsGradient.addColorStop(0, 'rgba(102, 126, 234, 0.3)');
chatsGradient.addColorStop(1, 'rgba(102, 126, 234, 0.05)');
// Create gradient for messages line
const messagesGradient = ctx.createLinearGradient(0, 0, 0, 300);
messagesGradient.addColorStop(0, 'rgba(118, 75, 162, 0.3)');
messagesGradient.addColorStop(1, 'rgba(118, 75, 162, 0.05)');
// Convert wp_localize_script objects to arrays (WordPress converts indexed arrays to objects)
const labels = Object.values(mxchatChartData.labels);
const chatsData = Object.values(mxchatChartData.chats).map(Number);
const messagesData = Object.values(mxchatChartData.messages).map(Number);
console.log('[MxChat Chart] Processed labels:', labels);
console.log('[MxChat Chart] Processed chatsData:', chatsData);
console.log('[MxChat Chart] Processed messagesData:', messagesData);
// Create chart
try {
canvas.chartInstance = new SimpleChart(canvas, {
labels: labels,
datasets: [
{
label: 'Chats',
data: chatsData,
borderColor: '#667eea',
backgroundColor: chatsGradient,
fill: true
},
{
label: 'Messages',
data: messagesData,
borderColor: '#764ba2',
backgroundColor: messagesGradient,
fill: true
}
]
});
console.log('[MxChat Chart] Chart created successfully');
} catch (error) {
console.error('[MxChat Chart] Error creating chart:', error);
}
}
// Initialize chart on page load (dashboard is shown by default)
setTimeout(function() {
initActivityChart();
}, 100);
// Reinitialize chart on window resize
let resizeTimeout;
$(window).on('resize', function() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
initActivityChart();
}, 250);
});
// ==========================================================================
// Leads Tab
// ==========================================================================
const leadsState = {
loaded: false,
page: 1,
perPage: 25,
totalPages: 1,
totalCount: 0,
selected: new Set(),
filters: {
search: '',
dateRange: 'all',
status: 'all',
pageUrl: '',
pageTitle: ''
},
pendingDelete: [],
leadsRows: [] // last-rendered rows for quick lookup
};
function $leads() { return $('#leads'); }
// Called after a transcript delete from the All Chats side. Marks the Leads tab
// data stale so the next tab visit re-fetches, and refreshes immediately if the
// Leads tab happens to already be visible.
function invalidateLeadsData() {
leadsState.loaded = false;
if ($('#leads').hasClass('active')) {
loadLeads(1);
}
}
function escapeHtmlLeads(s) {
if (s === null || typeof s === 'undefined') return '';
return String(s)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function leadsFiltersActive() {
const f = leadsState.filters;
return f.search !== '' || f.dateRange !== 'all' || f.status !== 'all' || f.pageUrl !== '';
}
function updateClearFiltersButton() {
if (leadsFiltersActive()) {
$('#mxch-leads-clear-filters').show();
} else {
$('#mxch-leads-clear-filters').hide();
}
}
function setPageFilterChip(url, title) {
leadsState.filters.pageUrl = url || '';
leadsState.filters.pageTitle = title || url || '';
const $chip = $('#mxch-leads-active-page-filter');
if (url) {
$chip.find('.mxch-leads-page-chip-label').text('Page: ' + (title || url));
$chip.show();
} else {
$chip.hide();
}
updateClearFiltersButton();
}
function loadLeads(page) {
if (typeof page === 'number') leadsState.page = page;
const $tbody = $('#mxch-leads-tbody');
$tbody.html('
|
');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'mxchat_fetch_leads',
page: leadsState.page,
per_page: leadsState.perPage,
search: leadsState.filters.search,
date_range: leadsState.filters.dateRange,
status: leadsState.filters.status,
page_url: leadsState.filters.pageUrl
},
success: function(response) {
leadsState.loaded = true;
if (!response || !response.success) {
$tbody.html('
| Error loading leads |
');
return;
}
leadsState.totalPages = response.total_pages || 1;
leadsState.totalCount = response.total_count || 0;
leadsState.leadsRows = response.leads || [];
renderLeadsStats(response.stats || {});
renderLeadsTopPages(response.top_pages || []);
renderLeadsTable(response.leads || []);
renderLeadsCount(response.showing_start, response.showing_end, response.total_count);
renderLeadsPagination(response.page, response.total_pages);
// Nav badge
if (response.stats && typeof response.stats.total_leads === 'number') {
const $badge = $('#mxch-leads-nav-badge');
if (response.stats.total_leads > 0) {
$badge.text(response.stats.total_leads).show();
} else {
$badge.hide();
}
}
},
error: function() {
$tbody.html('
| Error loading leads |
');
}
});
}
function renderLeadsStats(stats) {
$('#mxch-leads-stat-total').text(stats.total_leads || 0);
$('#mxch-leads-stat-new').text(stats.new_this_week || 0);
$('#mxch-leads-stat-avg').text(stats.avg_convos || 0);
const pct = stats.orphan_pct || 0;
$('#mxch-leads-stat-orphan').text(pct + '%');
const orphanCount = stats.orphan_count || 0;
$('#mxch-leads-stat-orphan-sub').text(orphanCount + (orphanCount === 1 ? ' lead captured but never chatted' : ' leads captured but never chatted'));
}
function renderLeadsTopPages(pages) {
const $wrap = $('#mxch-leads-toppages-list');
if (!pages || pages.length === 0) {
$wrap.html('
No page data yet.
');
return;
}
let html = '';
pages.forEach(function(p) {
const isActive = leadsState.filters.pageUrl === p.url ? ' is-active' : '';
html += `
`;
});
$wrap.html(html);
}
function renderLeadsTable(rows) {
const $tbody = $('#mxch-leads-tbody');
if (!rows || rows.length === 0) {
$tbody.html(`
No leads match the current filters.
|
`);
return;
}
let html = '';
rows.forEach(function(r) {
const emailKey = (r.email || '').toLowerCase();
const isChecked = leadsState.selected.has(emailKey) ? ' checked' : '';
// Status: 'active' (has conversations), 'chat_deleted' (admin removed the chat), 'orphan' (no chat ever).
const status = r.status || (r.is_orphan ? 'orphan' : 'active');
const isOrphan = (status === 'orphan');
const isChatDeleted = (status === 'chat_deleted');
const nameLine = r.name
? `
${escapeHtmlLeads(r.name)}`
: '';
const leadCell = `
${escapeHtmlLeads(r.email)}
${nameLine}
`;
let countCell;
if (isOrphan) {
countCell = `
Orphan`;
} else if (isChatDeleted) {
countCell = `
Chat deleted`;
} else {
countCell = `
${r.conversation_count}`;
}
const lastCell = escapeHtmlLeads(r.last_seen_display || (isOrphan ? 'No conversation yet' : ''));
const pageCell = r.top_page_url
? `
${escapeHtmlLeads(r.top_page_title || r.top_page_url)}`
: '
—';
// View Convo only for active leads (orphans and chat_deleted have no viewable session).
const viewBtn = (status === 'active' && r.latest_session_id)
? `
`
: '';
const deleteBtn = `
`;
const rowStateClass = isOrphan ? ' is-orphan' : (isChatDeleted ? ' is-chat-deleted' : '');
html += `
|
${leadCell} |
${countCell} |
${lastCell} |
${pageCell} |
${viewBtn}${deleteBtn} |
`;
});
$tbody.html(html);
updateLeadsSelectionUI();
}
function renderLeadsCount(start, end, total) {
if (!total) {
$('#mxch-leads-count').text('0 leads');
} else {
$('#mxch-leads-count').text(start + '-' + end + ' / ' + total + ' leads');
}
}
function renderLeadsPagination(currentPage, totalPages) {
const $c = $('#mxch-leads-pagination');
if (!totalPages || totalPages <= 1) { $c.html(''); return; }
let html = '';
$c.html(html);
}
function updateLeadsSelectionUI() {
const count = leadsState.selected.size;
const $countEl = $('#mxch-leads-selected-count');
const $del = $('#mxch-leads-delete-selected');
if (count > 0) {
$countEl.text(count + ' selected').addClass('has-selection');
$del.prop('disabled', false);
} else {
$countEl.text('0').removeClass('has-selection');
$del.prop('disabled', true);
}
// Selected-scope export menu items
$('#mxch-leads-export-menu button[data-scope="selected"]').prop('disabled', count === 0);
// Select-all checkbox state
const $checks = $('.mxch-leads-rowcheck');
const checked = $checks.filter(':checked').length;
const total = $checks.length;
$('#mxch-leads-select-all').prop('checked', total > 0 && checked === total);
$('#mxch-leads-select-all').prop('indeterminate', checked > 0 && checked < total);
}
// Trigger leads load when switching to the tab (works alongside the main nav handler above).
$('.mxch-nav-link[data-target="leads"], .mxch-mobile-nav-link[data-target="leads"]').on('click', function() {
if (!leadsState.loaded) {
loadLeads(1);
}
});
// Filter: search (debounced)
let leadsSearchTimer;
$('#mxch-leads-search').on('input', function() {
clearTimeout(leadsSearchTimer);
const val = $(this).val();
leadsSearchTimer = setTimeout(function() {
leadsState.filters.search = (val || '').trim();
updateClearFiltersButton();
loadLeads(1);
}, 300);
});
// Filter: date range
$('#mxch-leads-date-range').on('change', function() {
leadsState.filters.dateRange = $(this).val();
updateClearFiltersButton();
loadLeads(1);
});
// Filter: status
$('#mxch-leads-status').on('change', function() {
leadsState.filters.status = $(this).val();
updateClearFiltersButton();
loadLeads(1);
});
// Clear filters
$('#mxch-leads-clear-filters').on('click', function() {
leadsState.filters = { search: '', dateRange: 'all', status: 'all', pageUrl: '', pageTitle: '' };
$('#mxch-leads-search').val('');
$('#mxch-leads-date-range').val('all');
$('#mxch-leads-status').val('all');
setPageFilterChip('', '');
loadLeads(1);
});
// Remove page chip
$leads().on('click', '.mxch-leads-page-chip-remove', function() {
setPageFilterChip('', '');
loadLeads(1);
});
// Top Pages click -> set filter
$leads().on('click', '.mxch-leads-toppage-row', function() {
const url = $(this).data('url') || '';
const title = $(this).data('title') || '';
setPageFilterChip(url, title);
loadLeads(1);
});
// Pagination click
$leads().on('click', '#mxch-leads-pagination .mxch-page-btn', function() {
const p = parseInt($(this).data('page'), 10);
if (p > 0) loadLeads(p);
});
// Select-all
$('#mxch-leads-select-all').on('change', function() {
const on = $(this).is(':checked');
$('.mxch-leads-rowcheck').prop('checked', on);
$('.mxch-leads-row').each(function() {
const email = ($(this).data('email') || '').toString().toLowerCase();
if (on) {
leadsState.selected.add(email);
} else {
leadsState.selected.delete(email);
}
});
updateLeadsSelectionUI();
});
// Row checkbox
$leads().on('change', '.mxch-leads-rowcheck', function() {
const email = ($(this).closest('.mxch-leads-row').data('email') || '').toString().toLowerCase();
if ($(this).is(':checked')) {
leadsState.selected.add(email);
} else {
leadsState.selected.delete(email);
}
updateLeadsSelectionUI();
});
// View convo -> jump to All Chats tab and open the session
$leads().on('click', '.mxch-leads-view', function() {
const sid = $(this).attr('data-session-id');
if (!sid) return;
$('.mxch-nav-link[data-target="all-chats"]').trigger('click');
// selectChat is defined earlier in this closure
if (typeof selectChat === 'function') {
setTimeout(function() { selectChat(sid); }, 30);
}
});
// Row delete -> confirm for one
$leads().on('click', '.mxch-leads-delete-row', function() {
const email = $(this).data('email');
if (!email) return;
openLeadsConfirm([String(email)]);
});
// Bulk delete -> confirm for N
$('#mxch-leads-delete-selected').on('click', function() {
if (leadsState.selected.size === 0) return;
openLeadsConfirm(Array.from(leadsState.selected));
});
function openLeadsConfirm(emails) {
leadsState.pendingDelete = emails;
const count = emails.length;
const msg = count === 1
? 'Delete lead "' + emails[0] + '" and all of their conversations?'
: 'Delete ' + count + ' leads and all of their conversations?';
$('#mxch-leads-confirm-body').text(msg);
$('#mxch-leads-confirm').fadeIn(120);
}
function closeLeadsConfirm() {
$('#mxch-leads-confirm').fadeOut(120);
leadsState.pendingDelete = [];
}
$leads().on('click', '[data-mxch-leads-close]', closeLeadsConfirm);
$('#mxch-leads-confirm-go').on('click', function() {
const emails = leadsState.pendingDelete.slice();
if (!emails.length) { closeLeadsConfirm(); return; }
const $btn = $(this).prop('disabled', true).text('Deleting...');
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'mxchat_delete_leads',
security: $('#mxchat_leads_delete_nonce').val(),
emails: emails
},
success: function(response) {
$btn.prop('disabled', false).text('Delete permanently');
closeLeadsConfirm();
if (response && response.success) {
emails.forEach(function(e) { leadsState.selected.delete(e.toLowerCase()); });
loadLeads(leadsState.page);
} else {
alert((response && response.data && response.data.message) || 'Failed to delete leads.');
}
},
error: function() {
$btn.prop('disabled', false).text('Delete permanently');
alert('Network error while deleting.');
}
});
});
// Export dropdown
$('#mxch-leads-export-btn').on('click', function(e) {
e.stopPropagation();
$('#mxch-leads-export-menu').toggleClass('is-open');
});
$(document).on('click', function() {
$('#mxch-leads-export-menu').removeClass('is-open');
});
$('#mxch-leads-export-menu').on('click', function(e) { e.stopPropagation(); });
$('#mxch-leads-export-menu button').on('click', function() {
if ($(this).prop('disabled')) return;
const scope = $(this).data('scope') || 'all';
const fields = $(this).data('fields') || 'email_and_name';
submitLeadsExport(scope, fields);
$('#mxch-leads-export-menu').removeClass('is-open');
});
function submitLeadsExport(scope, fields) {
const $form = $('