# mxchat-basic/2.6.2/js/mxchat_transcripts.js

MxChat – AI Chatbot &amp; Content Generation for WordPress, version 2.6.2. 438 lines.

- Page: https://pluginprobe.com/plugins/mxchat-basic/2.6.2/code/js/mxchat_transcripts.js
- Raw: https://pluginprobe.com/plugins/mxchat-basic/2.6.2/raw/js/mxchat_transcripts.js
- Modified: 2025-12-27T13:38:16+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/mxchat-basic/2.6.2/code/js/mxchat_transcripts.js#L10-L20`.

```javascript
jQuery(document).ready(function($) {
    // Current page state
    let currentPage = 1;
    const perPage = 50; // Display 50 sessions per page
    let totalPages = 1;
    
    // Track selected sessions for bulk delete
    let selectedSessions = new Set();

    // Select/Deselect All functionality
    const selectButton = $('#mxchat-select-all-transcripts');
    let isSelected = false;

    selectButton.click(function() {
        isSelected = !isSelected;
        $(this).toggleClass('selected');
        
        // Update button text
        const buttonText = $(this).find('.button-text');
        buttonText.text(isSelected ? 'Deselect All' : 'Select All');
        
        // Update session selection (for current page)
        $('.mxchat-session-header').each(function() {
            const sessionId = $(this).data('session-id');
            const sessionContainer = $(this).closest('.mxchat-session');
            if (isSelected) {
                selectedSessions.add(sessionId);
                sessionContainer.addClass('selected');
            } else {
                selectedSessions.delete(sessionId);
                sessionContainer.removeClass('selected');
            }
        });
        
        updateDeleteButtonState();
    });

    // Search functionality
    $('#mxchat-search-transcripts').on('input', function() {
        var searchTerm = $(this).val().toLowerCase();
        
        if (searchTerm.length > 0) {
            // Reset to first page when searching
            currentPage = 1;
            
            // Load with search filter
            loadTranscripts(currentPage, searchTerm);
        } else {
            // Reset to first page with no search term
            currentPage = 1;
            loadTranscripts(currentPage, '');
        }
    });

    // Initial load of transcripts
    loadTranscripts(currentPage, '');

    // Function to load transcripts with pagination
    function loadTranscripts(page, searchTerm = '') {
        $('#mxchat-transcripts').html('<div class="mxchat-loading">Loading transcripts...</div>');
        
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'mxchat_fetch_chat_history',
                page: page,
                per_page: perPage,
                search: searchTerm
            },
            success: function(response) {
                $('#mxchat-transcripts').html(response.html);
                currentPage = response.page;
                totalPages = response.total_pages;
                
                // Reset selection state when page changes (but keep selectedSessions for bulk operations)
                isSelected = false;
                selectButton.removeClass('selected');
                selectButton.find('.button-text').text('Select All');
                
                // Restore selection state for sessions on this page
                $('.mxchat-session-header').each(function() {
                    const sessionId = $(this).data('session-id');
                    const sessionContainer = $(this).closest('.mxchat-session');
                    if (selectedSessions.has(sessionId)) {
                        sessionContainer.addClass('selected');
                    }
                });
                
                updateDeleteButtonState();
                
                // Add click handlers to pagination buttons
                $('.mxchat-pagination-button').on('click', function() {
                    var pageNum = $(this).data('page');
                    loadTranscripts(pageNum, searchTerm);
                    
                    // Scroll to top of transcripts
                    $('html, body').animate({
                        scrollTop: $('#mxchat-transcripts').offset().top - 50
                    }, 300);
                });
                
                // Re-attach event handlers for newly loaded content
                attachDynamicEventHandlers();
            },
            error: function(xhr, status, error) {
                $('#mxchat-transcripts').html('<div class="mxchat-error">Error loading chat transcripts. Please try again.</div>');
                console.error("AJAX Error: " + status + " - " + error);
            }
        });
    }
    
    // Attach event handlers to dynamically loaded content
    function attachDynamicEventHandlers() {
        // Handle individual delete button clicks
        $('.mxchat-delete-btn').off('click').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            
            const sessionId = $(this).data('session-id');
            
            if (!confirm("Are you sure you want to delete this chat session? This action cannot be undone.")) {
                return;
            }
            
            // Delete single session
            deleteSessions([sessionId]);
        });
        
        // Handle session header clicks for selection (bulk delete)
        $('.mxchat-session-header').off('click').on('click', function(e) {
            // Don't trigger if clicking the delete button
            if ($(e.target).hasClass('mxchat-delete-btn') || $(e.target).closest('.mxchat-delete-btn').length) {
                return;
            }

            const sessionId = $(this).data('session-id');
            const sessionContainer = $(this).closest('.mxchat-session');

            if (selectedSessions.has(sessionId)) {
                selectedSessions.delete(sessionId);
                sessionContainer.removeClass('selected');
            } else {
                selectedSessions.add(sessionId);
                sessionContainer.addClass('selected');
            }

            updateDeleteButtonState();
        });

        // Handle clicks on Sources link for RAG context
        $('.mxchat-rag-link').off('click').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();

            const messageId = $(this).closest('.mxchat-message').data('message-id');
            if (messageId) {
                openRagContextModal(messageId);
            }
        });
    }
    
    // Update delete button state based on selections
    function updateDeleteButtonState() {
        const deleteButton = $('.delete-chats-button');
        if (selectedSessions.size > 0) {
            deleteButton.prop('disabled', false);
        } else {
            deleteButton.prop('disabled', true);
        }
    }
    
    // Function to delete sessions
    function deleteSessions(sessionIds) {
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'mxchat_delete_chat_history',
                delete_session_ids: sessionIds,
                security: $('#mxchat_delete_chat_nonce').val()
            },
            success: function(response) {
                var jsonResponse = JSON.parse(response);
                if (jsonResponse.success) {
                    alert("Success: " + jsonResponse.success);
                    
                    // Remove deleted sessions from selectedSessions
                    sessionIds.forEach(id => selectedSessions.delete(id));
                    
                } else if (jsonResponse.error) {
                    alert("Error: " + jsonResponse.error);
                } else {
                    //console.log("Unexpected response format.");
                }
                
                // Reload the current page of transcripts
                loadTranscripts(currentPage);
            },
            error: function(xhr, status, error) {
                //console.error("AJAX Error: " + status + " - " + error);
                //console.log(xhr.responseText);
                alert("An error occurred while deleting chat sessions. Please try again.");
            }
        });
    }

    // Delete form submission (bulk delete)
    $('#mxchat-delete-form').submit(function(e) {
        e.preventDefault();
        
        if (selectedSessions.size === 0) {
            alert("Please select at least one chat session to delete.");
            return;
        }
        
        // Confirm deletion
        if (!confirm(`Are you sure you want to delete the selected ${selectedSessions.size} chat session(s)? This action cannot be undone.`)) {
            return;
        }
        
        // Convert Set to Array and delete
        deleteSessions(Array.from(selectedSessions));
    });
    
    // Export functionality - this remains unchanged as it should export all transcripts
    $('#mxchat-export-transcripts').on('click', function() {
        var $button = $(this);
        $button.prop('disabled', true).addClass('loading');

        // Create a form and submit it
        var $form = $('<form>', {
            'method': 'post',
            'action': ajaxurl
        });

        $form.append($('<input>', {
            'type': 'hidden',
            'name': 'action',
            'value': 'mxchat_export_transcripts'
        }));

        $form.append($('<input>', {
            'type': 'hidden',
            'name': 'security',
            'value': mxchatAdmin.export_nonce
        }));

        $form.appendTo('body').submit();

        // Re-enable the button after a short delay
        setTimeout(function() {
            $button.prop('disabled', false).removeClass('loading');
        }, 2000);
    });
    
    // Chat Email Notification Modal functionality
    
    // Open modal
    $('#mxchat-chat-email-notification-btn').on('click', function(e) {
        e.preventDefault();
        $('#mxchat-chat-email-notification-modal').fadeIn(300);
    });
    
    // Close modal
    $('.mxchat-chat-notification-modal-close, .mxchat-chat-notification-modal-cancel').on('click', function() {
        $('#mxchat-chat-email-notification-modal').fadeOut(300);
    });
    
    // Close modal on outside click
    $('#mxchat-chat-email-notification-modal').on('click', function(e) {
        if ($(e.target).is('#mxchat-chat-email-notification-modal')) {
            $(this).fadeOut(300);
        }
    });
    
    // Handle form submission - Let WordPress handle it normally for settings
    $('#mxchat-chat-email-notification-form').on('submit', function(e) {
        // Don't prevent default - let the form submit normally to WordPress options.php
        var $submitButton = $(this).find('button[type="submit"]');
        var originalText = $submitButton.text();

        // Just show a loading state
        $submitButton.text('Saving...').prop('disabled', true);

        // The form will submit normally and reload the page
    });

    // ========== RAG Context Modal Functions ==========

    // Open RAG context modal and fetch data
    function openRagContextModal(messageId) {
        const $modal = $('#mxchat-rag-context-modal');
        const $loading = $modal.find('.mxchat-rag-loading');
        const $content = $modal.find('.mxchat-rag-content');

        // Show modal with loading state
        $modal.fadeIn(300);
        $loading.show();
        $content.html('');

        // Fetch RAG context via AJAX
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: {
                action: 'mxchat_get_rag_context',
                message_id: messageId
            },
            success: function(response) {
                $loading.hide();
                if (response.success && response.data) {
                    renderRagContext(response.data, $content);
                } else {
                    $content.html('<div class="mxchat-rag-error">Unable to load document context.</div>');
                }
            },
            error: function() {
                $loading.hide();
                $content.html('<div class="mxchat-rag-error">Error loading document context. Please try again.</div>');
            }
        });
    }

    // Render RAG context data in the modal
    function renderRagContext(data, $container) {
        let html = '';

        // Summary section
        html += '<div class="mxchat-rag-summary">';
        html += '<div class="mxchat-rag-summary-item">';
        html += '<span class="mxchat-rag-label">Knowledge Base:</span> ';
        html += '<span class="mxchat-rag-value">' + escapeHtml(data.knowledge_base_type || 'WordPress Database') + '</span>';
        html += '</div>';
        html += '<div class="mxchat-rag-summary-item">';
        html += '<span class="mxchat-rag-label">Similarity Threshold:</span> ';
        html += '<span class="mxchat-rag-value">' + Math.round((data.similarity_threshold || 0.35) * 100) + '%</span>';
        html += '</div>';
        html += '<div class="mxchat-rag-summary-item">';
        html += '<span class="mxchat-rag-label">Documents Checked:</span> ';
        html += '<span class="mxchat-rag-value">' + (data.total_documents_checked || 0) + '</span>';
        html += '</div>';
        html += '</div>';

        // Top matches section
        if (data.top_matches && data.top_matches.length > 0) {
            html += '<div class="mxchat-rag-matches">';
            html += '<h3>Retrieved Documents</h3>';

            data.top_matches.forEach(function(match, index) {
                const isUsed = match.used_for_context;
                const isAboveThreshold = match.above_threshold;
                const cardClass = isUsed ? 'mxchat-rag-match-used' : (isAboveThreshold ? 'mxchat-rag-match-above' : 'mxchat-rag-match-below');
                const statusIcon = isUsed ? '✅' : (isAboveThreshold ? '⚠️' : '❌');
                const statusLabel = isUsed ? 'Used for Response' : (isAboveThreshold ? 'Above Threshold' : 'Below Threshold');

                html += '<div class="mxchat-rag-match-card ' + cardClass + '">';
                html += '<div class="mxchat-rag-match-header">';
                html += '<span class="mxchat-rag-match-rank">#' + (index + 1) + '</span>';
                html += '<span class="mxchat-rag-match-score">' + match.similarity_percentage + '%</span>';
                html += '<span class="mxchat-rag-match-status ' + (isUsed ? 'status-used' : (isAboveThreshold ? 'status-above' : 'status-below')) + '">';
                html += statusIcon + ' ' + statusLabel;
                html += '</span>';
                html += '</div>';

                html += '<div class="mxchat-rag-match-source">';
                if (match.source_display && match.source_display.startsWith('http')) {
                    html += '<a href="' + escapeHtml(match.source_display) + '" target="_blank" rel="noopener noreferrer">';
                    html += '🔗 ' + escapeHtml(match.source_display);
                    html += '</a>';
                } else {
                    html += '📄 ' + escapeHtml(match.source_display || 'Content snippet');
                }
                html += '</div>';

                if (match.content_preview) {
                    html += '<div class="mxchat-rag-match-preview">';
                    html += escapeHtml(match.content_preview);
                    html += '</div>';
                }

                // Show role restriction if not public
                if (match.role_restriction && match.role_restriction !== 'public') {
                    html += '<div class="mxchat-rag-match-meta">';
                    html += '<span class="mxchat-rag-role-badge">🔒 ' + escapeHtml(match.role_restriction) + '</span>';
                    html += '</div>';
                }

                html += '</div>';
            });

            html += '</div>';
        } else {
            html += '<div class="mxchat-rag-no-matches">No document matches found for this response.</div>';
        }

        // Approved URLs section
        if (data.approved_urls && data.approved_urls.length > 0) {
            html += '<div class="mxchat-rag-urls">';
            html += '<h3>Approved URLs for Citations (' + data.approved_urls.length + ')</h3>';
            html += '<ul class="mxchat-rag-url-list">';
            data.approved_urls.forEach(function(url) {
                html += '<li><a href="' + escapeHtml(url) + '" target="_blank" rel="noopener noreferrer">' + escapeHtml(url) + '</a></li>';
            });
            html += '</ul>';
            html += '</div>';
        }

        $container.html(html);
    }

    // Helper function to escape HTML
    function escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    // Close RAG context modal
    $('.mxchat-rag-modal-close').on('click', function() {
        $('#mxchat-rag-context-modal').fadeOut(300);
    });

    // Close modal on outside click
    $('#mxchat-rag-context-modal').on('click', function(e) {
        if ($(e.target).is('#mxchat-rag-context-modal')) {
            $(this).fadeOut(300);
        }
    });

    // Close modal on Escape key
    $(document).on('keydown', function(e) {
        if (e.key === 'Escape') {
            $('#mxchat-rag-context-modal').fadeOut(300);
        }
    });
});
```
