PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.4.5
MxChat – AI Chatbot & Content Generation for WordPress v1.4.5
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
mxchat-basic / js / chat-script.js

chat-script.js in MxChat – AI Chatbot & Content Generation for WordPress 1.4.5, at js/chat-script.js

738 lines 26.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 jQuery(document).ready(function($) {
2 //console.log('mxchatChat object:', mxchatChat);
3 //console.log('Link Target Toggle Value:', mxchatChat.link_target_toggle);
4
5
6 // Initialize color settings
7 var userMessageBgColor = mxchatChat.user_message_bg_color;
8 var userMessageFontColor = mxchatChat.user_message_font_color;
9 var botMessageBgColor = mxchatChat.bot_message_bg_color;
10 var botMessageFontColor = mxchatChat.bot_message_font_color;
11 var linkTarget = mxchatChat.link_target_toggle === 'on' ? '_blank' : '_self';
12
13
14
15
16 function getChatSession() {
17 var sessionId = getCookie('mxchat_session_id');
18 //console.log("Session ID retrieved from cookie: ", sessionId);
19
20 if (!sessionId) {
21 sessionId = generateSessionId();
22 //console.log("Generated new session ID: ", sessionId);
23 setChatSession(sessionId);
24 }
25
26 //console.log("Final session ID: ", sessionId);
27 return sessionId;
28 }
29
30 function setChatSession(sessionId) {
31 // Set the cookie with a 24-hour expiration (86400 seconds)
32 document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax";
33 }
34
35 // Get cookie value by name
36 function getCookie(name) {
37 let value = "; " + document.cookie;
38 let parts = value.split("; " + name + "=");
39 if (parts.length == 2) return parts.pop().split(";").shift();
40 }
41
42 // Generate a new session ID
43 function generateSessionId() {
44 return 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
45 }
46
47 // Function to send the message to the chatbot (backend)
48 function sendMessageToChatbot(message) {
49 var sessionId = getChatSession(); // Reuse the session ID logic
50
51 // Hide the popular questions section
52 $('#mxchat-popular-questions').hide();
53
54 // Show thinking indicator (no need to append the user's message again)
55 appendThinkingMessage();
56 scrollToBottom();
57
58 //console.log("Sending message to chatbot:", message); // Log the message
59 //console.log("Session ID:", sessionId); // Log the session ID
60
61 // Call the chatbot using the same call logic as sendMessage
62 callMxChat(message, function(response) {
63 // ** Ensure temporary thinking message is removed before adding new response **
64 $('.temporary-message').remove();
65
66 // Replace thinking indicator with actual response
67 replaceLastMessage("bot", response);
68 });
69 }
70
71
72
73
74
75 function sendMessage() {
76 var message = $('#chat-input').val();
77 if (message) {
78 appendMessage("user", message);
79 $('#chat-input').val('');
80
81 // Hide the popular questions section
82 $('#mxchat-popular-questions').hide();
83
84 // Show typing indicator
85 appendThinkingMessage();
86 scrollToBottom();
87
88 callMxChat(message, function(response) {
89 // Replace typing indicator with actual response
90 replaceLastMessage("bot", response);
91 });
92 }
93 }
94
95
96 // Function to append a thinking message with animation
97 function appendThinkingMessage() {
98 // Remove any existing thinking dots first
99 $('.thinking-dots').remove();
100
101 // Retrieve the bot message font color and background color
102 var botMessageFontColor = mxchatChat.bot_message_font_color;
103 var botMessageBgColor = mxchatChat.bot_message_bg_color;
104
105 var thinkingHtml = '<div class="thinking-dots-container">' +
106 '<div class="thinking-dots">' +
107 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
108 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
109 '<span class="dot" style="background-color: ' + botMessageFontColor + ';"></span>' +
110 '</div>' +
111 '</div>';
112
113 // Append the thinking dots to the chat container (or within the temporary message div)
114 $("#chat-box").append('<div class="bot-message temporary-message" style="background-color: ' + botMessageBgColor + ';">' + thinkingHtml + '</div>');
115 scrollToBottom();
116 }
117
118 // Trigger send button click when "Enter" key is pressed in the input field
119 $('#chat-input').keypress(function(e) {
120 if (e.which == 13) {
121 e.preventDefault();
122 $('#send-button').click();
123 }
124 });
125
126 // Handle send button click
127 $('#send-button').click(function() {
128 sendMessage();
129 });
130
131 // Handle click on popular questions
132 $('.mxchat-popular-question').on('click', function () {
133 var question = $(this).text(); // Get the text of the clicked question
134
135 // Append the question as if the user typed it
136 appendMessage("user", question);
137
138 // Send the question to the server (backend)
139 sendMessageToChatbot(question);
140 });
141
142
143 // Use the linkTarget in your linkify function
144 function linkify(inputText) {
145 // Check for already linked URLs and skip them
146 // We use negative lookaheads to skip anything already in an <a> tag
147 var markdownLinkPattern = /\[([^\]]+)\]\((https?:\/\/[^\s]+)\)/g;
148 var replacedText = inputText.replace(markdownLinkPattern, '<a href="$2" target="' + linkTarget + '">$1</a>');
149
150 // Replace standalone URLs not already in an <a> tag
151 var urlPattern = /(^|[^">])(https?:\/\/[^\s<]+)/gim;
152 replacedText = replacedText.replace(urlPattern, '$1<a href="$2" target="' + linkTarget + '">$2</a>');
153
154 // Replace "www." prefixed URLs not already in an <a> tag
155 var wwwPattern = /(^|[^">])(www\.[\S]+(\b|$))(?![^<]*<\/a>)/gim;
156 replacedText = replacedText.replace(wwwPattern, '$1<a href="http://$2" target="' + linkTarget + '">$2</a>');
157
158 return replacedText;
159 }
160
161
162 function scrollElementToTop(element) {
163 var chatBox = $('#chat-box');
164 var elementTop = element.position().top + chatBox.scrollTop();
165 chatBox.animate({ scrollTop: elementTop }, 500);
166 }
167
168
169 // Optimized scrollToBottom function for instant scrolling
170 function scrollToBottom(instant = false) {
171 var chatBox = $('#chat-box');
172 if (instant) {
173 // Instantly set the scroll position to the bottom
174 chatBox.scrollTop(chatBox.prop("scrollHeight"));
175 } else {
176 // Use requestAnimationFrame for smoother scrolling if needed
177 let start = null;
178 const scrollHeight = chatBox.prop("scrollHeight");
179 const initialScroll = chatBox.scrollTop();
180 const distance = scrollHeight - initialScroll;
181 const duration = 500; // Duration in ms
182
183 function smoothScroll(timestamp) {
184 if (!start) start = timestamp;
185 const progress = timestamp - start;
186 const currentScroll = initialScroll + (distance * (progress / duration));
187 chatBox.scrollTop(currentScroll);
188
189 if (progress < duration) {
190 requestAnimationFrame(smoothScroll);
191 } else {
192 chatBox.scrollTop(scrollHeight); // Ensure it's exactly at the bottom
193 }
194 }
195
196 requestAnimationFrame(smoothScroll);
197 }
198 }
199
200
201 // Function to format text with **bold** inside double asterisks
202 function formatBoldText(text) {
203 return text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
204 }
205
206 // Function to convert newline characters to HTML line breaks and handle paragraph spacing
207 function convertNewlinesToBreaks(text) {
208 var lines = text.split('\n');
209 var formattedText = '';
210
211 for (var i = 0; i < lines.length; i++) {
212 formattedText += lines[i] + '<br>';
213 }
214
215 return formattedText;
216 }
217
218 // Copy to clipboard function
219 // Function to copy text to clipboard
220 function copyToClipboard(text) {
221 var tempInput = $('<input>');
222 $('body').append(tempInput);
223 tempInput.val(text).select();
224 document.execCommand('copy');
225 tempInput.remove();
226 }
227
228
229 // Initialize session ID
230 var sessionId = getChatSession();
231
232 function callMxChat(message, callback) {
233 var sessionId = getChatSession();
234 //console.log("Calling chatbot with session ID:", sessionId); // Debugging session ID
235 //console.log("Message being sent:", message); // Debugging message
236
237 $.ajax({
238 url: mxchatChat.ajax_url,
239 type: 'POST',
240 dataType: 'json',
241 data: {
242 action: 'mxchat_handle_chat_request',
243 message: message,
244 session_id: sessionId,
245 nonce: mxchatChat.nonce
246 },
247 success: function(response) {
248 //console.log("Response from server:", response); // Debugging response
249
250 // Extract response data
251 var responseText = response.text || response.message || (response.data && response.data.message) || '';
252 var responseHtml = response.html || '';
253 var images = response.images || [];
254
255 if (responseText || responseHtml || images.length > 0) {
256 //console.log("Displaying response text:", responseText);
257 replaceLastMessage("bot", responseText, responseHtml, images);
258 } else {
259 //console.error("Empty response; showing fallback error.");
260 appendMessage("bot", "I'm sorry, something went wrong.");
261 }
262
263 // Handle redirection if specified
264 if (response.redirect_url) {
265 //console.log("Redirecting to URL:", response.redirect_url);
266 setTimeout(function() {
267 window.location.href = response.redirect_url;
268 }, 2000);
269 }
270 },
271 error: function(xhr, status, error) {
272 console.error("Error communicating with the server:", xhr.status, error);
273
274 try {
275 //console.log("Raw error response:", xhr.responseText);
276 var response = xhr.responseJSON || JSON.parse(xhr.responseText); // Parse the error response
277 var errorMessage = response?.data?.message
278 ? response.data.message
279 : "An unexpected error occurred.";
280
281 //console.log("Parsed error message:", errorMessage);
282
283 // Append the error message to the chat box
284 appendMessage("bot", errorMessage);
285 } catch (e) {
286 console.error("Error parsing server response:", e);
287 appendMessage("bot", "An unexpected error occurred.");
288 }
289 }
290 });
291 }
292
293
294 function appendMessage(sender, messageText = '', messageHtml = '', images = [], isTemporary = false) {
295 try {
296 var messageClass = sender === "user" ? "user-message" : "bot-message";
297 var bgColor = sender === "user" ? userMessageBgColor : botMessageBgColor;
298 var fontColor = sender === "user" ? userMessageFontColor : botMessageFontColor;
299
300 var messageDiv = $('<div>').addClass(messageClass).css({
301 'background': bgColor,
302 'color': fontColor
303 });
304
305 // Format the message text, including code blocks
306 var fullMessage = linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(messageText))));
307
308 if (images && images.length > 0) {
309 fullMessage += '<div class="image-gallery">';
310 images.forEach(img => {
311 fullMessage += `
312 <div style="margin-bottom: 10px;">
313 <strong>${img.title}</strong><br>
314 <a href="${img.image_url}" target="_blank">
315 <img src="${img.thumbnail_url}" alt="${img.title}" style="max-width: 100px; height: auto; margin: 5px;" />
316 </a>
317 </div>`;
318 });
319 fullMessage += '</div>';
320 }
321
322 if (messageHtml) {
323 fullMessage += '<br><br>' + messageHtml;
324 }
325
326 messageDiv.html(fullMessage);
327
328 if (isTemporary) {
329 messageDiv.addClass('temporary-message');
330 }
331
332 messageDiv.hide().appendTo('#chat-box').fadeIn(300, function() {
333 if (sender === "bot") {
334 // After bot's message is displayed, scroll last user message to top
335 var lastUserMessage = $('#chat-box').find('.user-message').last();
336 if (lastUserMessage.length) {
337 scrollElementToTop(lastUserMessage);
338 }
339 }
340 });
341 } catch (error) {
342 console.error("Error rendering message with images:", error);
343 }
344 }
345
346
347 function replaceLastMessage(sender, responseText, responseHtml = '', images = []) {
348 var messageClass = sender === "user" ? "user-message" : "bot-message";
349 var lastMessageDiv = $('#chat-box').find('.' + messageClass + '.temporary-message').last();
350
351 // Format response text, including code blocks
352 var fullMessage = Array.isArray(responseText) ?
353 responseText.map(item => linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(item))))).join("<br>") :
354 linkify(formatBoldText(convertNewlinesToBreaks(formatCodeBlocks(responseText))));
355
356 if (responseHtml) {
357 fullMessage += '<br><br>' + responseHtml;
358 }
359
360 if (images.length > 0) {
361 fullMessage += '<div class="image-gallery">';
362 images.forEach(img => {
363 fullMessage += `
364 <div style="margin-bottom: 10px;">
365 <strong>${img.title}</strong><br>
366 <a href="${img.image_url}" target="_blank">
367 <img src="${img.thumbnail_url}" alt="${img.title}" style="max-width: 100px; height: auto; margin: 5px;" />
368 </a>
369 </div>`;
370 });
371 fullMessage += '</div>';
372 }
373
374 if (lastMessageDiv.length) {
375 lastMessageDiv.fadeOut(200, function() {
376 $(this).html(fullMessage).removeClass('temporary-message').fadeIn(200, function() {
377 // After bot's message is displayed, scroll last user message to top
378 var lastUserMessage = $('#chat-box').find('.user-message').last();
379 if (lastUserMessage.length) {
380 scrollElementToTop(lastUserMessage);
381 }
382 });
383 });
384 } else {
385 appendMessage(sender, responseText, responseHtml, images);
386 }
387 }
388
389
390 function loadChatHistory() {
391 var sessionId = getChatSession();
392 var chatPersistenceEnabled = mxchatChat.chat_persistence_toggle === 'on';
393
394 if (chatPersistenceEnabled && sessionId) {
395 $.ajax({
396 url: mxchatChat.ajax_url,
397 type: 'POST',
398 dataType: 'json',
399 data: {
400 action: 'mxchat_fetch_conversation_history',
401 session_id: sessionId
402 },
403 success: function(response) {
404 if (response.success && response.data && Array.isArray(response.data.conversation)) {
405 var $chatBox = $('#chat-box');
406 var $fragment = $(document.createDocumentFragment());
407
408 $.each(response.data.conversation, function(index, message) {
409 var messageElement = $('<div>').addClass(message.role === 'user' ? 'user-message' : 'bot-message')
410 .css({
411 'background': message.role === 'user' ? userMessageBgColor : botMessageBgColor,
412 'color': message.role === 'user' ? userMessageFontColor : botMessageFontColor
413 });
414
415 var content = message.content;
416
417 // Decode any escaped characters
418 content = content.replace(/\\'/g, "'").replace(/\\"/g, '"');
419 content = decodeHTMLEntities(content);
420
421 // Detect if the content is HTML by checking for specific classes
422 if (content.includes("mxchat-product-card") || content.includes("mxchat-image-gallery")) {
423 // Append HTML content directly
424 messageElement.html(content);
425 } else {
426 // Format plain text content with code block support
427 var formattedContent = linkify(
428 formatBoldText(
429 convertNewlinesToBreaks(formatCodeBlocks(content))
430 )
431 );
432 messageElement.html(formattedContent);
433 }
434
435 $fragment.append(messageElement);
436 });
437
438 $chatBox.append($fragment);
439 scrollToBottom(true);
440
441 if (response.data.conversation.length > 0) {
442 $('#mxchat-popular-questions').hide();
443 }
444 } else {
445 console.warn("No conversation history found.");
446 }
447 },
448 error: function(xhr, status, error) {
449 console.error("Error loading chat history:", status, error);
450 appendMessage("bot", "Unable to load chat history.");
451 }
452 });
453 } else {
454 console.warn("Chat persistence is disabled or no session ID found. Not loading history.");
455 }
456 }
457
458
459 // Function to decode HTML entities
460 function decodeHTMLEntities(text) {
461 var textArea = document.createElement('textarea');
462 textArea.innerHTML = text;
463 return textArea.value;
464 }
465
466
467 function formatCodeBlocks(text) {
468 // Regex to match triple backticks and capture content between them
469 var codeBlockPattern = /```(\w+)?\n?([\s\S]+?)```/g;
470
471 return text.replace(codeBlockPattern, function(_, language, codeContent) {
472 language = language || 'plaintext';
473
474 // Wrap code content in <pre> and <code> tags
475 return `<div class="code-block-container">
476 <pre class="code-block"><code class="language-${language}">${escapeHtml(codeContent)}</code></pre>
477 </div>`;
478 });
479 }
480
481 function escapeHtml(unsafe) {
482 return unsafe
483 .replace(/&/g, "&amp;")
484 .replace(/</g, "&lt;")
485 .replace(/>/g, "&gt;")
486 .replace(/"/g, "&quot;")
487 .replace(/'/g, "&#039;");
488 }
489
490 // Function to convert newlines, skipping preformatted text
491 function convertNewlinesToBreaks(text) {
492 // Regex to exclude <pre> and <code> tags from adding <br> tags
493 return text.replace(/(^|[^>])\n/g, '$1<br>');
494 }
495
496
497
498 $(document).ready(function() {
499 loadChatHistory();
500 });
501
502
503
504 // Helper function to check if a string is an image HTML
505 function isImageHtml(str) {
506 return str.startsWith('<img') && str.endsWith('>');
507 }
508
509 // Function to remove thinking dots
510 function removeThinkingDots() {
511 $('.thinking-dots').closest('.temporary-message').remove();
512 }
513
514 function isMobile() {
515 // This can be a simple check, or more sophisticated detection of mobile devices
516 return window.innerWidth <= 768; // Example threshold for mobile devices
517 }
518
519 function disableScroll() {
520 if (isMobile()) {
521 $('body').css('overflow', 'hidden');
522 }
523 }
524
525 function enableScroll() {
526 if (isMobile()) {
527 $('body').css('overflow', '');
528 }
529 }
530
531 // Function to show the chatbot widget (moved outside the Complianz logic)
532 function showChatWidget() {
533 setTimeout(function() {
534 $('#floating-chatbot-button').css('display', 'flex').fadeTo(500, 1);
535 }, 250);
536 }
537
538 // Function to hide the chatbot widget
539 function hideChatWidget() {
540 $('#floating-chatbot-button').css('display', 'none');
541 }
542
543 // Pre-chat dismissal check function (wrapped in a function for reuse)
544 function checkPreChatDismissal() {
545 $.ajax({
546 url: mxchatChat.ajax_url,
547 type: 'POST',
548 data: {
549 action: 'mxchat_check_pre_chat_message_status',
550 _ajax_nonce: mxchatChat.nonce
551 },
552 success: function(response) {
553 if (response.success && !response.data.dismissed) {
554 $('#pre-chat-message').fadeIn(250);
555 } else {
556 $('#pre-chat-message').hide();
557 }
558 },
559 error: function() {
560 console.error('Failed to check pre-chat message dismissal status.');
561 }
562 });
563 }
564
565 // Function to dismiss pre-chat message for 24 hours
566 function handlePreChatDismissal() {
567 $('#pre-chat-message').fadeOut(200);
568 $.ajax({
569 url: mxchatChat.ajax_url,
570 type: 'POST',
571 data: {
572 action: 'mxchat_dismiss_pre_chat_message',
573 _ajax_nonce: mxchatChat.nonce
574 },
575 success: function() {
576 $('#pre-chat-message').hide();
577 },
578 error: function() {
579 console.error('Failed to dismiss pre-chat message.');
580 }
581 });
582 }
583
584 // Handle pre-chat message dismissal on button click
585 $(document).on('click', '.close-pre-chat-message', function(e) {
586 e.stopPropagation();
587 handlePreChatDismissal();
588 });
589
590 // Function for Complianz logic
591 var applyComplianzLogic = mxchatChat.complianz_toggle;
592 if (applyComplianzLogic) {
593 function checkConsentAndShowChat() {
594 var consentStatus = typeof cmplz_has_consent === "function" && cmplz_has_consent('marketing');
595 var consentType = typeof complianz !== 'undefined' ? complianz.consenttype : null;
596
597 // Show the chatbot by default
598 showChatWidget();
599
600 if (consentType === 'optin' && !consentStatus) {
601 // For opt-in, hide only if user explicitly denies consent
602 hideChatWidget();
603 } else if (consentType === 'optout' && consentStatus === false) {
604 // For opt-out, hide only if user explicitly denies consent
605 hideChatWidget();
606 } else {
607 // Keep showing the chatbot
608 showChatWidget();
609 }
610
611 checkPreChatDismissal(); // Ensure we check dismissal after consent is handled
612 }
613
614 // Initial check when the page loads
615 checkConsentAndShowChat();
616
617 // Listen for changes in consent status
618 $(document).on('cmplz_status_change', function(event, category) {
619 if (category === 'marketing') {
620 checkConsentAndShowChat();
621 }
622 });
623 } else {
624 // If Complianz is not toggled on, always show the chatbot
625 showChatWidget();
626 checkPreChatDismissal(); // Always check pre-chat dismissal when consent logic is not applied
627 }
628
629 // Toggle chatbot visibility on floating button click
630 $(document).on('click', '#floating-chatbot-button', function() {
631 var chatbot = $('#floating-chatbot');
632 if (chatbot.hasClass('hidden')) {
633 chatbot.removeClass('hidden').addClass('visible');
634 $(this).addClass('hidden');
635 disableScroll();
636 // Hide the pre-chat message without dismissing it
637 $('#pre-chat-message').fadeOut(250);
638 } else {
639 chatbot.removeClass('visible').addClass('hidden');
640 $(this).removeClass('hidden');
641 enableScroll();
642 // Show the pre-chat message again if it hasn't been dismissed
643 checkPreChatDismissal();
644 }
645 });
646
647 $(document).on('click', '#exit-chat-button', function() {
648 $('#floating-chatbot').addClass('hidden').removeClass('visible');
649 $('#floating-chatbot-button').removeClass('hidden');
650 enableScroll();
651 });
652
653 // Close pre-chat message on click
654 $(document).on('click', '.close-pre-chat-message', function(e) {
655 e.stopPropagation(); // Prevent triggering the parent .pre-chat-message click
656 $('#pre-chat-message').fadeOut(200, function() {
657 $(this).remove();
658 });
659 });
660
661 // Open chatbot when pre-chat message is clicked
662 $(document).on('click', '#pre-chat-message', function() {
663 var chatbot = $('#floating-chatbot');
664 if (chatbot.hasClass('hidden')) {
665 chatbot.removeClass('hidden').addClass('visible');
666 $('#floating-chatbot-button').addClass('hidden');
667 $('#pre-chat-message').fadeOut(250); // Hide pre-chat message
668 disableScroll(); // Disable scroll when chatbot opens
669 }
670 });
671
672 // If the chatbot is initially hidden, ensure the button is visible
673 if ($('#floating-chatbot').hasClass('hidden')) {
674 $('#floating-chatbot-button').removeClass('hidden');
675 }
676
677 function setFullHeight() {
678 var vh = $(window).innerHeight() * 0.01;
679 $(':root').css('--vh', vh + 'px');
680 }
681
682 // Set the height when the page loads
683 $(document).ready(function() {
684 setFullHeight();
685 });
686
687 // Set the height on resize and orientation change events
688 $(window).on('resize orientationchange', function() {
689 setFullHeight();
690 });
691
692
693 // Now handle the close button to dismiss the pre-chat message for 24 hours
694 var closeButton = document.querySelector('.close-pre-chat-message');
695 if (closeButton) {
696 closeButton.addEventListener('click', function() {
697 $('#pre-chat-message').fadeOut(200); // Hide the message
698
699 // Send an AJAX request to set the transient flag for 24 hours
700 $.ajax({
701 url: mxchatChat.ajax_url,
702 type: 'POST',
703 data: {
704 action: 'mxchat_dismiss_pre_chat_message',
705 _ajax_nonce: mxchatChat.nonce
706 },
707 success: function() {
708 //console.log('Pre-chat message dismissed for 24 hours.');
709
710 // Ensure the message is hidden after dismissal
711 $('#pre-chat-message').hide();
712 },
713 error: function() {
714 //console.error('Failed to dismiss pre-chat message.');
715 }
716 });
717 });
718 }
719
720
721
722
723 // Event listener for Add to Cart button
724 $(document).on('click', '.mxchat-add-to-cart-button', function() {
725 var productId = $(this).data('product-id'); // Get product ID from data attribute
726
727 // Simulate user message first for proper ordering
728 appendMessage("user", "add to cart"); // Display the user's "add to cart" message first
729
730
731 // Use existing function to send the "add to cart" command to the chatbot
732 sendMessageToChatbot("add to cart"); // Triggers the chatbot response as though user typed it
733 });
734
735
736
737 });
738