PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.4
MxChat – AI Chatbot & Content Generation for WordPress v1.4
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-admin.js +159 -508 2.0.51.4 View file →
@@ -1,361 +1,113 @@
1 -// Simple debounce function implementation
2 -function debounce(func, wait) {
3 - let timeout;
4 - return function executedFunction(...args) {
5 - const later = () => {
6 - clearTimeout(timeout);
7 - func(...args);
8 - };
9 - clearTimeout(timeout);
10 - timeout = setTimeout(later, wait);
11 - };
12 -}
1 +jQuery(document).ready(function($) {
13 2
14 -// Helper function to open edit modal
15 -function mxchatOpenEditModal(intentId, phrases) {
16 - const modal = document.getElementById('mxchat-edit-modal');
17 - if (!modal) return;
18 -
19 - // Get form fields
20 - const intentIdField = document.getElementById('edit_intent_id');
21 - const phrasesField = document.getElementById('edit_phrases');
22 -
23 - // Set values
24 - intentIdField.value = intentId;
25 - phrasesField.value = phrases;
26 -
27 - // Show modal with animation
28 - modal.style.display = 'flex';
29 - requestAnimationFrame(() => {
30 - modal.classList.add('active');
3 + $('.mxchat-nav-tab').on('click', function(e) {
4 + e.preventDefault();
5 + $('.mxchat-nav-tab').removeClass('mxchat-nav-tab-active');
6 + $(this).addClass('mxchat-nav-tab-active');
7 + $('.mxchat-tab-content').removeClass('active').hide();
8 + var activeTab = $(this).attr('href');
9 + $(activeTab).addClass('active').show();
31 10 });
32 11
33 - // Set up close handlers
34 - const closeModal = () => {
35 - modal.classList.remove('active');
36 - setTimeout(() => {
37 - modal.style.display = 'none';
38 - }, 300); // Match the CSS transition time
39 - };
12 + // Activate the first tab by default
13 + $('.mxchat-nav-tab-active').trigger('click');
40 14
41 - // Close button handler
42 - const closeBtn = modal.querySelector('.mxchat-modal-close');
43 - if (closeBtn) {
44 - closeBtn.onclick = closeModal;
45 - }
46 -
47 - // Cancel button handler
48 - const cancelBtn = modal.querySelector('.mxchat-modal-cancel');
49 - if (cancelBtn) {
50 - cancelBtn.onclick = closeModal;
51 - }
52 -
53 - // Click outside modal to close
54 - modal.onclick = (e) => {
55 - if (e.target === modal) {
56 - closeModal();
15 + // Toggle visibility of API key
16 + $('#toggleApiKeyVisibility').on('click', function() {
17 + var apiKeyInput = $('#api_key');
18 + if (apiKeyInput.attr('type') === 'password') {
19 + apiKeyInput.attr('type', 'text');
20 + $(this).text('Hide');
21 + } else {
22 + apiKeyInput.attr('type', 'password');
23 + $(this).text('Show');
57 24 }
58 - };
59 -
60 - // Focus the textarea
61 - phrasesField.focus();
62 -}
63 -
64 -// Initialize event listeners
65 -document.addEventListener('DOMContentLoaded', () => {
66 - // Set up edit button handlers
67 - document.querySelectorAll('.mxchat-edit-button').forEach(button => {
68 - button.onclick = () => {
69 - const intentId = button.dataset.intentId;
70 - const phrases = button.dataset.phrases;
71 - mxchatOpenEditModal(intentId, phrases);
72 - };
73 25 });
74 -});
75 -
76 -jQuery(document).ready(function($) {
77 - // Ensure we have a debounce function (use lodash if available, otherwise use our implementation)
78 - const useDebounce = (window._ && window._.debounce) ? window._.debounce : debounce;
79 -
80 - // --- AJAX Auto-Save ---
81 - const $autosaveSections = $('.mxchat-autosave-section');
82 -
83 - if ($autosaveSections.length) {
84 - // Handle real-time range slider value updates
85 - $autosaveSections.find('input[type="range"]').on('input', function() {
86 - const value = $(this).val();
87 - $('#threshold_value').text(value);
88 - });
89 -
90 - // Handle all input changes (including range slider)
91 - $autosaveSections.find('input, textarea, select').on('change', function() {
92 - const $field = $(this);
93 - const name = $field.attr('name');
94 - let value;
95 -
96 - // Handle different input types
97 - if ($field.attr('type') === 'checkbox') {
98 - value = $field.is(':checked') ? 'on' : 'off';
99 - } else {
100 - value = $field.val();
101 - }
102 -
103 - // Create feedback container
104 - const feedbackContainer = $('<div class="feedback-container"></div>');
105 - const spinner = $('<div class="saving-spinner"></div>');
106 - const successIcon = $('<div class="success-icon">✔</div>');
107 -
108 - // Position feedback container based on input type
109 - if ($field.closest('.toggle-switch').length) {
110 - $field.closest('td').append(feedbackContainer);
111 - } else if ($field.closest('.mxchat-toggle-switch').length) {
112 - $field.closest('.mxchat-toggle-container').append(feedbackContainer);
113 - } else if ($field.closest('.slider-container').length) {
114 - $field.closest('.slider-container').after(feedbackContainer);
115 - } else {
116 - $field.after(feedbackContainer);
117 - }
118 - feedbackContainer.append(spinner);
119 -
120 - // Determine which AJAX action and nonce to use:
121 - var ajaxAction, nonce;
122 - // Use the new AJAX action for submenu fields:
123 - if ( name.indexOf('mxchat_prompts_options') !== -1 ||
124 - name === 'mxchat_auto_sync_posts' ||
125 - name === 'mxchat_auto_sync_pages' ) {
126 - ajaxAction = 'mxchat_save_prompts_setting';
127 - nonce = mxchatPromptsAdmin.prompts_setting_nonce;
128 - } else {
129 - // Otherwise, use the existing AJAX action.
130 - ajaxAction = 'mxchat_save_setting';
131 - nonce = mxchatAdmin.setting_nonce;
132 - }
133 -
134 - // AJAX save request
135 - $.ajax({
136 - url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
137 - type: 'POST',
138 - data: {
139 - action: ajaxAction,
140 - name: name,
141 - value: value,
142 - _ajax_nonce: nonce
143 - },
144 - success: function(response) {
145 - if (response.success) {
146 - spinner.fadeOut(200, function() {
147 - feedbackContainer.append(successIcon);
148 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
149 - feedbackContainer.remove();
150 - });
151 - });
152 - } else {
153 - alert('Error saving: ' + (response.data?.message || 'Unknown error'));
154 - if ($field.attr('type') === 'checkbox') {
155 - $field.prop('checked', !$field.is(':checked'));
156 - }
157 - feedbackContainer.remove();
158 - }
159 - },
160 - error: function() {
161 - alert('An error occurred while saving.');
162 - if ($field.attr('type') === 'checkbox') {
163 - $field.prop('checked', !$field.is(':checked'));
164 - }
165 - feedbackContainer.remove();
166 - }
167 - });
168 - });
169 -
170 - // Initialize color pickers with debouncing
171 - $autosaveSections.find('.my-color-field').each(function() {
172 - const $colorField = $(this);
173 -
174 - $(this).wpColorPicker({
175 - change: useDebounce(function(event, ui) {
176 - // Safety check - ensure we have a valid field and value
177 - if (!$colorField || !$colorField.val()) {
178 - console.warn('Color picker not ready');
179 - return;
180 - }
181 -
182 - const name = $colorField.attr('name');
183 - const value = $colorField.val();
184 -
185 - if (!name || !value) {
186 - console.warn('Missing required color picker values');
187 - return;
188 - }
189 -
190 - // Create feedback container
191 - const feedbackContainer = $('<div class="feedback-container"></div>');
192 - const spinner = $('<div class="saving-spinner"></div>');
193 - const successIcon = $('<div class="success-icon">✔</div>');
194 -
195 - // Position feedback container
196 - $colorField.closest('.wp-picker-container').after(feedbackContainer);
197 - feedbackContainer.append(spinner);
198 -
199 - // Determine AJAX action and nonce for color fields:
200 - var ajaxAction, nonce;
201 - if ( name.indexOf('mxchat_prompts_options') !== -1 ||
202 - name === 'mxchat_auto_sync_posts' ||
203 - name === 'mxchat_auto_sync_pages' ) {
204 - ajaxAction = 'mxchat_save_prompts_setting';
205 - nonce = mxchatPromptsAdmin.prompts_setting_nonce;
206 - } else {
207 - ajaxAction = 'mxchat_save_setting';
208 - nonce = mxchatAdmin.setting_nonce;
209 - }
210 -
211 - // AJAX save request
212 - $.ajax({
213 - url: (ajaxAction === 'mxchat_save_prompts_setting') ? mxchatPromptsAdmin.ajax_url : mxchatAdmin.ajax_url,
214 - type: 'POST',
215 - data: {
216 - action: ajaxAction,
217 - name: name,
218 - value: value,
219 - _ajax_nonce: nonce
220 - },
221 - success: function(response) {
222 - if (response.success) {
223 - spinner.fadeOut(200, function() {
224 - feedbackContainer.append(successIcon);
225 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
226 - feedbackContainer.remove();
227 - });
228 - });
229 - } else {
230 - alert('Error saving: ' + (response.data?.message || 'Unknown error'));
231 - feedbackContainer.remove();
232 - }
233 - },
234 - error: function() {
235 - alert('An error occurred while saving.');
236 - feedbackContainer.remove();
237 - }
238 - });
239 - }, 500)
240 - });
241 - });
242 -
243 - // Reinitialize color pickers when switching tabs
244 - $('.mxchat-nav-tab').on('click.mxchat', function() {
245 - setTimeout(function() {
246 - $('.my-color-field:visible').wpColorPicker('close');
247 - }, 100);
248 - });
249 - }
250 -
251 - // Initialize tabs system
252 - function initTabs() {
253 - // Remove any existing handlers first
254 - $('.mxchat-nav-tab').off('click.mxchat');
255 -
256 - // Add new click handlers
257 - $('.mxchat-nav-tab').on('click.mxchat', function(e) {
258 - e.preventDefault();
259 - e.stopPropagation();
260 -
261 - var $this = $(this);
262 -
263 - // Get tab ID - try href first, fallback to data-tab, then to default
264 - var tabId = $this.attr('href');
265 - if (tabId) {
266 - tabId = tabId.replace('#', '');
267 - } else {
268 - tabId = $this.data('tab') || 'chatbot';
269 - }
270 -
271 - // Safety check for empty tabId
272 - if (!tabId) {
273 - console.warn('No tab identifier found');
274 - return;
275 - }
276 -
277 - // Update tabs
278 - $('.mxchat-nav-tab').removeClass('mxchat-nav-tab-active');
279 - $this.addClass('mxchat-nav-tab-active');
280 -
281 - // Update content areas - with safety check
282 - $('.mxchat-tab-content').removeClass('active').hide();
283 - var $targetTab = $('#' + tabId);
284 - if ($targetTab.length) {
285 - $targetTab.addClass('active').show();
286 -
287 - // Store active tab
288 - try {
289 - localStorage.setItem('mxchat_active_tab', tabId);
290 - } catch (e) {
291 - console.warn('LocalStorage not available:', e);
292 - }
293 - } else {
294 - console.warn('Tab content #' + tabId + ' not found');
295 - }
296 - });
297 - }
298 26
299 - // Initialize tabs and handle events
300 - initTabs();
301 - $(document).on('widget-added widget-updated postbox-toggled', initTabs);
27 + // Toggle visibility of WooCommerce Consumer Secret
28 + $('#toggleWooCommerceSecretVisibility').on('click', function() {
29 + var secretInput = $('#woocommerce_consumer_secret');
30 + if (secretInput.attr('type') === 'password') {
31 + secretInput.attr('type', 'text');
32 + $(this).text('Hide');
33 + } else {
34 + secretInput.attr('type', 'password');
35 + $(this).text('Show');
36 + }
37 + });
302 38
303 - // Activate initial tab
304 - try {
305 - var savedTab = localStorage.getItem('mxchat_active_tab');
306 - if (savedTab && $('#' + savedTab).length > 0) {
307 - $('.mxchat-nav-tab[href="#' + savedTab + '"]').trigger('click.mxchat');
39 + // Toggle visibility of Loops API Key
40 + $('#toggleLoopsApiKeyVisibility').on('click', function() {
41 + var loopsApiKeyInput = $('#loops_api_key');
42 + if (loopsApiKeyInput.attr('type') === 'password') {
43 + loopsApiKeyInput.attr('type', 'text');
44 + $(this).text('Hide');
308 45 } else {
309 - $('.mxchat-nav-tab').first().trigger('click.mxchat');
46 + loopsApiKeyInput.attr('type', 'password');
47 + $(this).text('Show');
310 48 }
311 - } catch (e) {
312 - $('.mxchat-nav-tab').first().trigger('click.mxchat');
313 - }
49 + });
314 50
315 - // Attach edit modal event handler
316 - $(document).on('click', '.mxchat-edit-button', function() {
317 - const intentId = $(this).data('intent-id');
318 - const phrases = $(this).data('phrases');
319 - mxchatOpenEditModal(intentId, phrases);
51 + // Toggle visibility of X.AI API Key
52 + $('#toggleXaiApiKeyVisibility').on('click', function() {
53 + var xaiApiKeyInput = $('#xai_api_key');
54 + if (xaiApiKeyInput.attr('type') === 'password') {
55 + xaiApiKeyInput.attr('type', 'text');
56 + $(this).text('Hide');
57 + } else {
58 + xaiApiKeyInput.attr('type', 'password');
59 + $(this).text('Show');
60 + }
320 61 });
321 62
322 - // Toggle visibility handlers
323 - function toggleVisibility(selector) {
324 - $(selector).on('click', function() {
325 - var inputField = $(this).prev('input');
326 - if (inputField.attr('type') === 'password') {
327 - inputField.attr('type', 'text');
328 - $(this).text('Hide');
329 - } else {
330 - inputField.attr('type', 'password');
331 - $(this).text('Show');
332 - }
333 - });
334 - }
63 + // Toggle visibility of Claude API Key
64 + $('#toggleClaudeApiKeyVisibility').on('click', function() {
65 + var claudeApiKeyInput = $('#claude_api_key');
66 + if (claudeApiKeyInput.attr('type') === 'password') {
67 + claudeApiKeyInput.attr('type', 'text');
68 + $(this).text('Hide');
69 + } else {
70 + claudeApiKeyInput.attr('type', 'password');
71 + $(this).text('Show');
72 + }
73 + });
335 74
336 - // Initialize all toggle visibility buttons
337 - [
338 - '#toggleApiKeyVisibility',
339 - '#toggleWooCommerceSecretVisibility',
340 - '#toggleLoopsApiKeyVisibility',
341 - '#toggleXaiApiKeyVisibility',
342 - '#toggleClaudeApiKeyVisibility',
343 - '#toggleBraveApiKeyVisibility',
344 - '#toggleWebhookUrlVisibility',
345 - '#toggleSecretKeyVisibility',
346 - '#toggleBotTokenVisibility',
347 - '#toggleDeepSeekApiKeyVisibility'
348 - ].forEach(toggleVisibility);
75 + // Toggle visibility of Brave API Key
76 + $('#toggleBraveApiKeyVisibility').on('click', function() {
77 + var braveApiKeyInput = $('#brave_api_key');
78 + if (braveApiKeyInput.attr('type') === 'password') {
79 + braveApiKeyInput.attr('type', 'text');
80 + $(this).text('Hide');
81 + } else {
82 + braveApiKeyInput.attr('type', 'password');
83 + $(this).text('Show');
84 + }
85 + });
86 +
349 87
350 - // Add Intent Form Submission
351 - $('#mxchat-add-intent-form').on('submit', function(event) {
352 - $('#mxchat-intent-loading').show();
353 - $('#mxchat-intent-loading-text').show();
354 - $(this).find('button[type="submit"]').hide();
88 +const $addIntentButton = $('button[name="mxchat_add_intent"]');
89 +
90 + // Handle the Add Intent form submission
91 + $('form').on('submit', function(event) {
92 + if ($addIntentButton.length) {
93 + // Show loading spinner and text, hide the add intent button on form submission
94 + $('#mxchat-intent-loading').show();
95 + $('#mxchat-loading-text-intent').show();
96 + $addIntentButton.hide();
97 + }
355 98 });
99 +
100 + // Hide loader and show Add Intent button after form submission completes
101 + $(document).ajaxComplete(function(event, xhr, settings) {
102 + if (settings.url.includes('admin-post.php')) {
103 + $('#mxchat-intent-loading').hide();
104 + $('#mxchat-loading-text-intent').hide();
105 + $addIntentButton.show();
106 + }
107 + });
356 108
357 - // Inline Edit Functionality
109 + // Click the Edit button
358 110 $('.edit-button').on('click', function() {
359 111 var row = $(this).closest('tr');
360 112 row.find('.content-view, .url-view').hide();
361 113 row.find('.content-edit, .url-edit').show();
@@ -361,10 +113,10 @@
361 113 row.find('.content-edit, .url-edit').show();
362 114 row.find('.edit-button').hide();
363 115 row.find('.save-button').show();
364 116 });
365 -
366 - // Save button handler
117 +
118 + // Click the Save button
367 119 $('.save-button').on('click', function() {
368 120 var button = $(this);
369 121 var row = button.closest('tr');
370 122 var id = button.data('id');
@@ -369,14 +121,12 @@
369 121 var row = button.closest('tr');
370 122 var id = button.data('id');
371 123 var newContent = row.find('.content-edit').val();
372 124 var newUrl = row.find('.url-edit').val();
373 -
374 - button.prop('disabled', true);
375 - button.text('Saving...');
376 -
125 +
126 + // Send an AJAX request to save the changes
377 127 $.ajax({
378 - url: mxchatAdmin.ajax_url,
128 + url: ajaxurl, // ajaxurl is automatically available in WP admin
379 129 type: 'POST',
380 130 data: {
381 131 action: 'mxchat_save_inline_prompt',
382 132 id: id,
@@ -381,190 +131,91 @@
381 131 action: 'mxchat_save_inline_prompt',
382 132 id: id,
383 133 article_content: newContent,
384 134 article_url: newUrl,
385 - _ajax_nonce: mxchatAdmin.inline_edit_nonce
135 + _ajax_nonce: mxchatInlineEdit.nonce // Use localized nonce
386 136 },
387 137 success: function(response) {
388 - button.prop('disabled', false);
389 - button.text('Save');
390 -
391 138 if (response.success) {
392 139 row.find('.content-view').html(newContent.replace(/\n/g, "<br>"));
393 - if (newUrl) {
394 - row.find('.url-view').html('<a href="' + newUrl + '" target="_blank">' + newUrl + '</a>');
395 - } else {
396 - row.find('.url-view').html('N/A');
397 - }
398 -
140 + row.find('.url-view a').attr('href', newUrl).text(newUrl);
399 141 row.find('.content-edit, .url-edit').hide();
400 142 row.find('.content-view, .url-view').show();
401 143 row.find('.save-button').hide();
402 144 row.find('.edit-button').show();
403 145 } else {
404 - alert('Error saving content: ' + (response.data?.message || 'Unknown error'));
146 + alert('Error saving content.');
405 147 }
406 148 },
407 149 error: function() {
408 - button.prop('disabled', false);
409 - button.text('Save');
410 - alert('An error occurred while saving.');
150 + alert('An error occurred.');
411 151 }
412 152 });
413 153 });
414 154
415 - // Activation handling
416 - const form = $('#mxchat-activation-form');
417 - const spinner = $('#mxchat-activation-spinner');
418 - const submitButton = $('#activate_license_button');
419 - const licenseStatus = $('#mxchat-license-status');
420 -
421 - if (form.length && licenseStatus.length && submitButton.length) {
422 - function handleActivationResponse(response) {
423 - spinner.hide();
424 - if (response.success) {
425 - licenseStatus.text('Active');
426 - licenseStatus.removeClass('inactive').addClass('active');
427 - form.hide();
428 - } else {
429 - licenseStatus.text('Inactive');
430 - alert(response.data || 'Activation failed. Please check your input.');
431 - submitButton.prop('disabled', false);
432 - }
155 +
156 +});
157 +
158 +jQuery(document).ready(function($) {
159 + console.log('Activation script loaded within mxchat-admin.js'); // Confirm script is loading
160 +
161 + // Select activation-related elements
162 + var form = $('#mxchat-activation-form');
163 + var spinner = $('#mxchat-activation-spinner');
164 + var submitButton = $('#activate_license_button');
165 + var licenseStatus = $('#mxchat-license-status');
166 +
167 + // Ensure essential elements exist
168 + if (form.length === 0 || licenseStatus.length === 0 || submitButton.length === 0) {
169 + console.error("Essential activation elements are missing from the page.");
170 + return;
171 + }
172 +
173 + // Function to handle the response from the activation AJAX request
174 + function handleActivationResponse(response) {
175 + spinner.hide(); // Hide the spinner
176 +
177 + if (response.success) {
178 + // Update UI on successful activation
179 + licenseStatus.text('Active');
180 + licenseStatus.removeClass('inactive').addClass('active');
181 +
182 + // Hide the activation form after successful activation
183 + form.hide();
184 + } else {
185 + licenseStatus.text('Inactive');
186 + alert(response.data || 'Activation failed. Please check your input.');
187 + submitButton.prop('disabled', false); // Re-enable button on failure
433 188 }
434 -
435 - form.on('submit', function(event) {
436 - event.preventDefault();
437 - spinner.show();
438 - submitButton.prop('disabled', true);
439 -
440 - var formData = {
441 - action: 'mxchat_activate_license',
442 - mxchat_pro_email: $('#mxchat_pro_email').val(),
443 - mxchat_activation_key: $('#mxchat_activation_key').val(),
444 - security: mxchatAdmin.license_nonce
445 - };
446 -
447 - $.post(mxchatAdmin.ajax_url, formData, function(response) {
448 - handleActivationResponse(response);
449 - }).fail(function() {
450 - alert('Server error. Please try again.');
451 - spinner.hide();
452 - submitButton.prop('disabled', false);
453 - });
454 - });
455 189 }
456 -
457 - // Questions handling
458 - $('.mxchat-add-question').on('click', function () {
459 - const container = $('#mxchat-additional-questions-container');
460 - const questionCount = container.find('.mxchat-question-row').length + 4;
461 - const questionIndex = container.find('.mxchat-question-row').length;
462 -
463 - const newQuestion = `
464 - <div class="mxchat-question-row">
465 - <input type="text"
466 - name="additional_popular_questions[]"
467 - placeholder="Enter Additional Popular Question ${questionCount}"
468 - class="regular-text mxchat-question-input"
469 - data-question-index="${questionIndex}" />
470 - <button type="button" class="button mxchat-remove-question"
471 - aria-label="Remove question">Remove</button>
472 - </div>
473 - `;
474 - container.append(newQuestion);
475 - });
476 -
477 - $(document).on('click', '.mxchat-remove-question', function () {
478 - $(this).closest('.mxchat-question-row').remove();
479 - saveQuestions();
480 - });
481 -
482 - $(document).on('change', '.mxchat-question-input', function() {
483 - saveQuestions();
484 - });
485 -
486 - function saveQuestions() {
487 - const questions = [];
488 - $('.mxchat-question-input').each(function() {
489 - const value = $(this).val().trim();
490 - if (value) {
491 - questions.push(value);
492 - }
493 - });
494 -
495 - const feedbackContainer = $('<div class="feedback-container"></div>');
496 - const spinner = $('<div class="saving-spinner"></div>');
497 - const successIcon = $('<div class="success-icon">✔</div>');
498 -
499 - // Append feedback after the add button
500 - $('.mxchat-add-question').after(feedbackContainer);
501 - feedbackContainer.append(spinner);
502 -
503 - // Save via AJAX
504 - $.ajax({
505 - url: mxchatAdmin.ajax_url,
506 - type: 'POST',
507 - data: {
508 - action: 'mxchat_save_setting',
509 - name: 'additional_popular_questions',
510 - value: JSON.stringify(questions),
511 - _ajax_nonce: mxchatAdmin.setting_nonce
512 - },
513 - success: function(response) {
514 - if (response.success) {
515 - spinner.fadeOut(200, function() {
516 - feedbackContainer.append(successIcon);
517 - successIcon.fadeIn(200).delay(1000).fadeOut(200, function() {
518 - feedbackContainer.remove();
519 - });
520 - });
521 - } else {
522 - alert('Error saving questions: ' + (response.data?.message || 'Unknown error'));
523 - feedbackContainer.remove();
524 - }
525 - },
526 - error: function() {
527 - alert('An error occurred while saving questions.');
528 - feedbackContainer.remove();
529 - }
530 - });
531 - }
532 -
533 - // Live agent status handler
534 - const statusToggle = document.getElementById('live_agent_status');
535 - const statusText = statusToggle?.parentElement.nextElementSibling?.querySelector('.status-text');
536 - if (statusToggle && statusText) {
537 - statusToggle.addEventListener('change', function() {
538 - // Update display text
539 - statusText.textContent = this.checked ? 'Online' : 'Offline';
540 -
541 - // Send the correct on/off value to the server
542 - if (window.mxchatSaveSetting) {
543 - window.mxchatSaveSetting('live_agent_status', this.checked ? 'on' : 'off');
544 - }
545 - });
546 - }
547 -
548 - // Function to adjust the textarea height to content
549 - function adjustTextareaHeight() {
550 - this.style.height = 'auto'; // Reset to auto to calculate scrollHeight
551 - this.style.height = this.scrollHeight + 'px'; // Expand to content height
552 - }
553 190
554 - // Function to reset the textarea height to initial
555 - function resetTextareaHeight() {
556 - this.style.height = ''; // Remove inline height, reverting to CSS default
557 - }
191 + // Event listener for form submission to activate the license
192 + form.on('submit', function(event) {
193 + event.preventDefault(); // Prevent the default form submission
194 + console.log("Activating license...");
558 195
559 - // Target the specific textarea by ID
560 - var $textarea = $('#system_prompt_instructions');
196 + // Show spinner and disable the submit button to prevent multiple submissions
197 + spinner.show();
198 + submitButton.prop('disabled', true);
561 199
562 - // Bind events
563 - $textarea.on('focus input', adjustTextareaHeight) // Expand on focus and input
564 - .on('blur', resetTextareaHeight); // Reset on blur
565 -
566 -
200 + // Gather form data
201 + var formData = {
202 + action: 'mxchat_activate_license',
203 + mxchat_pro_email: $('#mxchat_pro_email').val(),
204 + mxchat_activation_key: $('#mxchat_activation_key').val(),
205 + security: mxchatAdmin.nonce // Ensure this is localized in PHP
206 + };
207 +
208 + // Send the AJAX request using jQuery
209 + $.post(mxchatAdmin.ajax_url, formData, function(response) {
210 + console.log("Activation response received:", response);
211 + handleActivationResponse(response);
212 + }).fail(function() {
213 + alert('Server error. Please try again.');
214 + spinner.hide();
215 + submitButton.prop('disabled', false);
216 + });
217 + });
567 218 });
568 219
569 220
570 221