PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.8
MxChat – AI Chatbot & Content Generation for WordPress v3.2.8
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | js/mxchat_transcripts.js +65 -5 3.2.33.2.8 View file →
@@ -216,15 +216,64 @@
216 216 $('#mxch-select-all').prop('checked', totalItems > 0 && checkedItems === totalItems);
217 217 $('#mxch-select-all').prop('indeterminate', checkedItems > 0 && checkedItems < totalItems);
218 218 }
219 219
220 - // Sort button
221 - $('#mxch-sort-btn').on('click', function() {
222 - currentSortOrder = currentSortOrder === 'desc' ? 'asc' : 'desc';
223 - $(this).find('svg').css('transform', currentSortOrder === 'asc' ? 'rotate(180deg)' : 'rotate(0deg)');
224 - loadChatList(currentPage, $('#mxch-search-transcripts').val());
220 + // Sort button — opens a small menu with 4 sort modes (plan-a5b006 adds rating sorts).
221 + $('#mxch-sort-btn').on('click', function(e) {
222 + e.stopPropagation();
223 + const $btn = $(this);
224 + let $menu = $('#mxch-sort-menu');
225 + if (!$menu.length) {
226 + $menu = $(
227 + '<div id="mxch-sort-menu" class="mxch-sort-menu" role="menu">' +
228 + ' <button type="button" class="mxch-sort-option" data-sort="desc" role="menuitem">Newest first</button>' +
229 + ' <button type="button" class="mxch-sort-option" data-sort="asc" role="menuitem">Oldest first</button>' +
230 + ' <button type="button" class="mxch-sort-option" data-sort="rating_positive" role="menuitem"><span class="mxch-sort-option-icon mxch-rating-thumb-up"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H7"/><path d="M3 10h4"/></svg></span>Positive ratings first</button>' +
231 + ' <button type="button" class="mxch-sort-option" data-sort="rating_negative" role="menuitem"><span class="mxch-sort-option-icon mxch-rating-thumb-down"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 14V2"/><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H17"/><path d="M21 14h-4"/></svg></span>Negative ratings first</button>' +
232 + '</div>'
233 + );
234 + $('body').append($menu);
235 + $menu.on('click', '.mxch-sort-option', function() {
236 + currentSortOrder = $(this).data('sort');
237 + $menu.find('.mxch-sort-option').removeClass('active');
238 + $(this).addClass('active');
239 + $menu.hide();
240 + loadChatList(1, $('#mxch-search-transcripts').val());
241 + });
242 + $(document).on('click.mxchSortMenu', function(ev) {
243 + if (!$(ev.target).closest('#mxch-sort-menu, #mxch-sort-btn').length) {
244 + $menu.hide();
245 + }
246 + });
247 + }
248 + $menu.find('.mxch-sort-option').removeClass('active');
249 + $menu.find('[data-sort="' + currentSortOrder + '"]').addClass('active');
250 + const offset = $btn.offset();
251 + const btnHeight = $btn.outerHeight();
252 + $menu.css({
253 + position: 'absolute',
254 + top: (offset.top + btnHeight + 4) + 'px',
255 + left: offset.left + 'px'
256 + }).toggle();
225 257 });
226 258
259 + // Render a rating badge for a session row. Uses inline SVG so the glyph
260 + // renders the same across OSes (emoji fonts vary). Tooltip surfaces the
261 + // optional feedback text.
262 + function renderRatingBadge(session) {
263 + const value = (session && typeof session.rating_value === 'number') ? session.rating_value : null;
264 + const feedback = (session && session.rating_feedback) ? session.rating_feedback : '';
265 + if (value === 1) {
266 + const title = feedback ? ('Visitor: ' + feedback) : 'Visitor rated this chat positively';
267 + return '<span class="mxch-chat-rating mxch-chat-rating-up" title="' + escapeHtml(title) + '" aria-label="' + escapeHtml(title) + '"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 10v12"/><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H7"/><path d="M3 10h4"/></svg></span>';
268 + }
269 + if (value === -1) {
270 + const title = feedback ? ('Visitor: ' + feedback) : 'Visitor rated this chat negatively';
271 + return '<span class="mxch-chat-rating mxch-chat-rating-down" title="' + escapeHtml(title) + '" aria-label="' + escapeHtml(title) + '"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 14V2"/><path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H17"/><path d="M21 14h-4"/></svg></span>';
272 + }
273 + return '<span class="mxch-chat-rating mxch-chat-rating-empty" title="No rating yet" aria-label="No rating yet">—</span>';
274 + }
275 +
227 276 // Delete selected button — opens the shared confirm modal with the "also delete lead" checkbox.
228 277 $('#mxch-delete-selected').on('click', function() {
229 278 const count = selectedSessions.size;
230 279 if (count === 0) return;
@@ -366,8 +415,9 @@
366 415 <div class="mxch-chat-name">${escapeHtml(session.display_name)}</div>
367 416 <div class="mxch-chat-preview">${escapeHtml(session.preview)}</div>
368 417 </div>
369 418 <div class="mxch-chat-meta">
419 + ${renderRatingBadge(session)}
370 420 <span class="mxch-chat-time">${escapeHtml(session.time_display)}</span>
371 421 <span class="mxch-chat-count">${session.message_count}</span>
372 422 </div>
373 423 </div>
@@ -518,8 +568,18 @@
518 568 $('#mxch-detail-email').text(data.user.email);
519 569 $('#mxch-detail-email-row').show();
520 570 } else {
521 571 $('#mxch-detail-email-row').hide();
572 + }
573 +
574 + // Feedback row — .text() (not .html()) for XSS-safe display of user-submitted text.
575 + // rating_feedback is already sanitize_text_field()'d + mb_substr(200) on save.
576 + var feedback = (data && data.rating_feedback) ? String(data.rating_feedback).trim() : '';
577 + if (feedback) {
578 + $('#mxch-detail-feedback').text(feedback);
579 + $('#mxch-detail-feedback-row').show();
580 + } else {
581 + $('#mxch-detail-feedback-row').hide();
522 582 }
523 583
524 584 // Clicked links
525 585 if (data.clicked_urls && data.clicked_urls.length > 0) {