testing progress

This commit is contained in:
2025-08-12 09:12:54 -07:00
parent 75fae0fbdb
commit e18e046431
7 changed files with 372 additions and 119 deletions

View File

@@ -131,10 +131,10 @@ jQuery(document).ready(function($) {
formDataString += '&action=twp_save_schedule&nonce=' + twp_ajax.nonce;
console.log('Submitting schedule form data:', formDataString);
// console.log('Submitting schedule form data:', formDataString);
$.post(twp_ajax.ajax_url, formDataString, function(response) {
console.log('Schedule save response:', response);
// console.log('Schedule save response:', response);
if (response.success) {
closeScheduleModal();
location.reload();
@@ -258,9 +258,7 @@ jQuery(document).ready(function($) {
var step = workflowSteps.find(function(s) { return s.id === stepId; });
if (!step) return;
console.log('Opening step config modal for step ID:', stepId, 'type:', stepType);
console.log('Step data:', step);
console.log('Step data.data:', step.data);
// console.log('Opening step config modal for step ID:', stepId, 'type:', stepType);
$('#step-id').val(stepId);
$('#step-type').val(stepType);
@@ -277,11 +275,19 @@ jQuery(document).ready(function($) {
// Show as overlay with proper flexbox positioning
$('#step-config-modal').css('display', 'flex').addClass('show');
// Additional debugging: Log all voice selects and their data-current values
setTimeout(function() {
$('#step-config-modal .voice-select').each(function() {
var $select = $(this);
// console.log('Voice select found in modal - data-current:', $select.data('current'), 'current val:', $select.val());
});
}, 100);
// If it's a schedule step, load the schedules
if (stepType === 'schedule_check') {
console.log('Setting up schedule step - current data:', step.data);
// console.log('Setting up schedule step - current data:', step.data);
setTimeout(function() {
console.log('About to load schedules, current select element:', $('#schedule-select'));
// console.log('About to load schedules, current select element:', $('#schedule-select'));
loadSchedulesForStep();
}, 100);
}
@@ -298,14 +304,54 @@ jQuery(document).ready(function($) {
// If it's an IVR step, load queues for any existing queue actions
if (stepType === 'ivr_menu') {
// console.log('Setting up IVR step - current data:', step.data);
setTimeout(function() {
// console.log('Loading queues for IVR step...');
$('#step-config-modal .target-queue').each(function() {
var $select = $(this);
if ($select.is(':visible')) {
loadQueuesForSelect($select);
}
var currentValue = $select.data('current');
// console.log('Loading queue for select with current value:', currentValue);
loadQueuesForSelect($select);
});
}, 100);
// Also load voices if TTS is selected for the step
if (step.data && step.data.audio_type === 'tts') {
// console.log('Loading voices for TTS step...');
var $voiceSelect = $('#step-config-modal .voice-select');
if ($voiceSelect.length) {
// Ensure the data-current attribute is properly set
if (!$voiceSelect.data('current') && step.data.voice_id) {
$voiceSelect.attr('data-current', step.data.voice_id);
$voiceSelect.data('current', step.data.voice_id);
// console.log('Manually set data-current to:', step.data.voice_id);
}
// console.log('Voice select found, loading voices with current:', $voiceSelect.data('current'));
loadWorkflowVoices($voiceSelect[0]);
} else {
// console.log('No voice select found');
}
}
}, 500); // Increased timeout even more
}
// For greeting and voicemail steps, auto-load voices if TTS is selected
if ((stepType === 'greeting' || stepType === 'voicemail') && step.data && step.data.audio_type === 'tts') {
// console.log('Setting up', stepType, 'step with TTS - voice_id:', step.data.voice_id);
setTimeout(function() {
var $voiceSelect = $('#step-config-modal .voice-select');
if ($voiceSelect.length) {
// Ensure the data-current attribute is properly set
if (!$voiceSelect.data('current') && step.data.voice_id) {
$voiceSelect.attr('data-current', step.data.voice_id);
$voiceSelect.data('current', step.data.voice_id);
// console.log('Manually set data-current to:', step.data.voice_id);
}
// console.log('Voice select found for', stepType, 'with data-current:', $voiceSelect.data('current'));
loadWorkflowVoices($voiceSelect[0]);
} else {
// console.log('No voice select found for', stepType);
}
}, 300);
}
}
@@ -344,7 +390,12 @@ jQuery(document).ready(function($) {
html += '<label>Voice:</label>';
html += '<select name="voice_id" class="voice-select" data-current="' + (data.voice_id || '') + '">';
html += '<option value="">Default voice</option>';
// If we have a saved voice, show it
if (data.voice_id && data.voice_name) {
html += '<option value="' + data.voice_id + '" selected>' + data.voice_name + '</option>';
}
html += '</select>';
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
html += '</div>';
@@ -380,7 +431,12 @@ jQuery(document).ready(function($) {
html += '<label>Voice:</label>';
html += '<select name="voice_id" class="voice-select" data-current="' + (data.voice_id || '') + '">';
html += '<option value="">Default voice</option>';
// If we have a saved voice, show it
if (data.voice_id && data.voice_name) {
html += '<option value="' + data.voice_id + '" selected>' + data.voice_name + '</option>';
}
html += '</select>';
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
html += '</div>';
@@ -441,7 +497,12 @@ jQuery(document).ready(function($) {
html += '<label>Voice:</label>';
html += '<select name="voice_id" class="voice-select" data-current="' + (data.voice_id || '') + '">';
html += '<option value="">Default voice</option>';
// If we have a saved voice, show it
if (data.voice_id && data.voice_name) {
html += '<option value="' + data.voice_id + '" selected>' + data.voice_name + '</option>';
}
html += '</select>';
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
html += '</div>';
@@ -475,7 +536,12 @@ jQuery(document).ready(function($) {
html += '<label>Voice:</label>';
html += '<select name="voice_id" class="voice-select" data-current="' + (data.voice_id || '') + '">';
html += '<option value="">Default voice</option>';
// If we have a saved voice, show it
if (data.voice_id && data.voice_name) {
html += '<option value="' + data.voice_id + '" selected>' + data.voice_name + '</option>';
}
html += '</select>';
html += '<input type="hidden" name="voice_name" value="' + (data.voice_name || '') + '">';
html += '<button type="button" class="button button-small" onclick="loadWorkflowVoices(this)">Load Voices</button>';
html += '</div>';
@@ -490,7 +556,7 @@ jQuery(document).ready(function($) {
break;
case 'schedule_check':
console.log('Generating schedule_check form with data:', data);
// console.log('Generating schedule_check form with data:', data);
html += '<div class="step-config-section">';
html += '<h4>Schedule Check Settings</h4>';
html += '<label>Select Schedule:</label>';
@@ -498,7 +564,7 @@ jQuery(document).ready(function($) {
html += '<option value="">Loading schedules...</option>';
html += '</select>';
html += '<p class="description">Uses WordPress timezone: ' + twp_ajax.timezone + '</p>';
console.log('Schedule ID being set:', (data.schedule_id || ''));
// console.log('Schedule ID being set:', (data.schedule_id || ''));
html += '</div>';
html += '<div class="step-config-section">';
@@ -506,15 +572,15 @@ jQuery(document).ready(function($) {
html += '<p class="description">Define what happens when calls come in outside business hours:</p>';
html += '<div id="after-hours-steps" class="after-hours-steps-container">';
html += '<div class="after-hours-step-list">';
console.log('Generating after-hours steps HTML, data:', data.after_hours_steps);
// console.log('Generating after-hours steps HTML, data:', data.after_hours_steps);
if (data.after_hours_steps && data.after_hours_steps.length > 0) {
console.log('Found', data.after_hours_steps.length, 'after-hours steps');
// console.log('Found', data.after_hours_steps.length, 'after-hours steps');
data.after_hours_steps.forEach(function(step, index) {
console.log('Generating HTML for after-hours step', index, ':', step);
// console.log('Generating HTML for after-hours step', index, ':', step);
html += generateAfterHoursStepHtml(step, index);
});
} else {
console.log('No after-hours steps found');
// console.log('No after-hours steps found');
html += '<p class="no-steps-message">No after-hours steps configured. Add steps below.</p>';
}
html += '</div>';
@@ -569,12 +635,17 @@ jQuery(document).ready(function($) {
// Forward action - phone number input
html += '<input type="text" name="target[]" class="target-forward" placeholder="Phone Number" value="' +
(option.action === 'forward' ? (option.number || option.target || '') : '') +
'" style="display: ' + (option.action === 'forward' || !option.action ? 'block' : 'none') + ';">';
'" style="display: ' + (option.action === 'forward' || !option.action ? 'block' : 'none') + ';" ' +
(option.action !== 'forward' && option.action ? 'disabled' : '') + '>';
// Queue action - queue dropdown
html += '<select name="target[]" class="target-queue queue-select" data-current="' +
(option.action === 'queue' ? (option.queue_id || option.target || '') : '') +
'" style="display: ' + (option.action === 'queue' ? 'block' : 'none') + ';">';
var queueCurrent = '';
if (option.action === 'queue') {
queueCurrent = option.queue_id || option.target || option.number || '';
}
html += '<select name="target[]" class="target-queue queue-select" data-current="' + queueCurrent +
'" style="display: ' + (option.action === 'queue' ? 'block' : 'none') + ';" ' +
(option.action !== 'queue' ? 'disabled' : '') + '>';
html += '<option value="">Select queue...</option>';
// Queue options will be populated by loadQueues function
html += '</select>';
@@ -582,12 +653,14 @@ jQuery(document).ready(function($) {
// Voicemail action - message input
html += '<input type="text" name="target[]" class="target-voicemail" placeholder="Voicemail Message" value="' +
(option.action === 'voicemail' ? (option.message || option.target || '') : '') +
'" style="display: ' + (option.action === 'voicemail' ? 'block' : 'none') + ';">';
'" style="display: ' + (option.action === 'voicemail' ? 'block' : 'none') + ';" ' +
(option.action !== 'voicemail' ? 'disabled' : '') + '>';
// Message action - message input
html += '<input type="text" name="target[]" class="target-message" placeholder="Message Text" value="' +
(option.action === 'message' ? (option.message || option.target || '') : '') +
'" style="display: ' + (option.action === 'message' ? 'block' : 'none') + ';">';
'" style="display: ' + (option.action === 'message' ? 'block' : 'none') + ';" ' +
(option.action !== 'message' ? 'disabled' : '') + '>';
html += '</div>';
html += '<button type="button" class="button button-small remove-ivr-option" onclick="removeIvrOption(this)">Remove</button>';
@@ -678,26 +751,23 @@ jQuery(document).ready(function($) {
};
window.loadSchedulesForStep = function() {
console.log('Loading schedules for step modal');
// console.log('Loading schedules for step modal');
$.post(twp_ajax.ajax_url, {
action: 'twp_get_schedules',
nonce: twp_ajax.nonce
}, function(response) {
console.log('Schedule response:', response);
// console.log('Schedule response:', response);
if (response.success) {
var $select = $('#schedule-select');
var currentScheduleId = $select.data('current') || $select.val();
console.log('Current schedule ID to select:', currentScheduleId);
console.log('Available schedules:', response.data.length);
console.log('Select element found:', $select.length > 0);
console.log('Select element name attribute:', $select.attr('name'));
// console.log('Current schedule ID to select:', currentScheduleId);
var options = '<option value="">Select a schedule...</option>';
response.data.forEach(function(schedule) {
var selected = (schedule.id == currentScheduleId) ? ' selected' : '';
options += '<option value="' + schedule.id + '"' + selected + '>' + schedule.schedule_name + '</option>';
console.log('Added schedule option:', schedule.schedule_name, 'ID:', schedule.id, 'Selected:', selected);
// console.log('Added schedule option:', schedule.schedule_name, 'ID:', schedule.id, 'Selected:', selected);
});
$select.html(options);
@@ -706,7 +776,7 @@ jQuery(document).ready(function($) {
setTimeout(function() {
if (currentScheduleId) {
$select.val(currentScheduleId);
console.log('Set schedule select value to:', currentScheduleId, 'Current value:', $select.val());
// console.log('Set schedule select value to:', currentScheduleId, 'Current value:', $select.val());
// Force trigger change event to ensure any listeners are notified
$select.trigger('change');
@@ -745,9 +815,9 @@ jQuery(document).ready(function($) {
// Parse form data into step data
step.data = parseStepFormData(stepType, formData);
console.log('Saved step data:', step);
// console.log('Saved step data:', step);
if (stepType === 'schedule_check') {
console.log('Saved schedule step data:', step.data);
// console.log('Saved schedule step data:', step.data);
}
updateWorkflowDisplay();
@@ -757,11 +827,10 @@ jQuery(document).ready(function($) {
function parseStepFormData(stepType, formData) {
var data = {};
console.log('Parsing form data for step type:', stepType);
console.log('Raw form data:', formData);
// console.log('Parsing form data for step type:', stepType);
formData.forEach(function(field) {
console.log('Processing field:', field.name, '=', field.value);
// console.log('Processing field:', field.name, '=', field.value);
if (field.name === 'use_tts') {
data.use_tts = true;
@@ -780,7 +849,12 @@ jQuery(document).ready(function($) {
}
});
console.log('Parsed data object:', data);
// console.log('Parsed data object:', data);
// Debug voice_id field specifically for greeting/IVR steps
if ((stepType === 'greeting' || stepType === 'ivr_menu') && data.voice_id) {
// console.log('Found voice_id in', stepType, 'step:', data.voice_id);
}
// For queue steps, also save the queue name for display purposes
if (stepType === 'queue' && data.queue_id) {
@@ -800,15 +874,33 @@ jQuery(document).ready(function($) {
// Handle IVR options specially
if (stepType === 'ivr_menu' && data.digit) {
// console.log('Processing IVR options - raw data:', data);
data.options = {};
for (var i = 0; i < data.digit.length; i++) {
data.options[data.digit[i]] = {
var option = {
action: data.action[i],
description: data.description[i],
number: data.target[i],
queue_name: data.target[i],
message: data.target[i]
};
// console.log('Processing option', i, '- action:', data.action[i], 'target:', data.target[i]);
// For queue action, get the actual queue name from the select option text
if (data.action[i] === 'queue' && data.target[i]) {
var $queueSelect = $('#step-config-form .ivr-option:eq(' + i + ') .target-queue');
var selectedOption = $queueSelect.find('option:selected');
// console.log('Queue select for option', i, ':', $queueSelect.length ? 'found' : 'not found');
if (selectedOption.length && selectedOption.text() !== 'Select queue...') {
option.queue_name = selectedOption.text();
option.queue_id = data.target[i];
// console.log('Set queue_name to:', option.queue_name, 'queue_id to:', option.queue_id);
}
}
// console.log('Final option', i, ':', option);
data.options[data.digit[i]] = option;
}
delete data.digit;
delete data.action;
@@ -818,7 +910,7 @@ jQuery(document).ready(function($) {
// Handle schedule check after-hours steps
if (stepType === 'schedule_check') {
console.log('Parsing schedule_check step data:', data);
// console.log('Parsing schedule_check step data:', data);
var afterHoursSteps = [];
@@ -852,9 +944,7 @@ jQuery(document).ready(function($) {
return step && step.type;
});
console.log('Parsed schedule_check data:', data);
console.log('After hours steps count:', data.after_hours_steps.length);
console.log('After hours steps:', data.after_hours_steps);
// console.log('Parsed schedule_check data:', data);
}
return data;
@@ -1030,26 +1120,26 @@ jQuery(document).ready(function($) {
// Load workflow data
currentWorkflowId = workflowId;
console.log('Loading workflow data:', workflow.workflow_data);
// console.log('Loading workflow data:', workflow.workflow_data);
if (workflow.workflow_data) {
try {
var workflowData = JSON.parse(workflow.workflow_data);
workflowSteps = workflowData.steps || [];
console.log('Parsed workflow steps:', workflowSteps);
// console.log('Parsed workflow steps:', workflowSteps);
// Debug schedule steps specifically
workflowSteps.forEach(function(step, index) {
if (step.type === 'schedule_check') {
console.log('Found schedule step at index', index, ':', step);
// console.log('Found schedule step at index', index, ':', step);
}
});
} catch (e) {
console.error('Error parsing workflow data:', e);
console.log('Raw workflow data that failed to parse:', workflow.workflow_data);
// console.log('Raw workflow data that failed to parse:', workflow.workflow_data);
workflowSteps = [];
}
} else {
console.log('No workflow data found');
// console.log('No workflow data found');
workflowSteps = [];
}
@@ -1121,7 +1211,7 @@ jQuery(document).ready(function($) {
var queue = response.data;
$('#queue-id').val(queue.id);
$('[name="queue_name"]').val(queue.queue_name);
$('[name="phone_number"]').val(queue.phone_number);
$('[name="notification_number"]').val(queue.notification_number);
$('[name="agent_group_id"]').val(queue.agent_group_id);
$('[name="max_size"]').val(queue.max_size);
$('[name="timeout_seconds"]').val(queue.timeout_seconds);
@@ -1464,8 +1554,9 @@ jQuery(document).ready(function($) {
window.loadQueues = function(button) {
var $button = $(button);
var $select = $button.prev('select.queue-select');
var currentValue = $select.data('current');
var currentValue = $select.attr('data-current') || $select.val() || '';
// console.log('loadQueues - currentValue from data-current:', currentValue);
$button.text('Loading...').prop('disabled', true);
$.post(twp_ajax.ajax_url, {
@@ -1494,50 +1585,106 @@ jQuery(document).ready(function($) {
// Load queues for a specific select element (used in IVR options)
function loadQueuesForSelect($select) {
var currentValue = $select.data('current') || $select.val();
var currentValue = $select.attr('data-current') || $select.val() || '';
// console.log('loadQueuesForSelect called with currentValue:', currentValue);
$.post(twp_ajax.ajax_url, {
action: 'twp_get_all_queues',
nonce: twp_ajax.nonce
}, function(response) {
// console.log('Queue loading response:', response);
if (response.success) {
var options = '<option value="">Select queue...</option>';
response.data.forEach(function(queue) {
var selected = queue.id == currentValue ? ' selected' : '';
options += '<option value="' + queue.id + '"' + selected + '>' + queue.queue_name + '</option>';
// console.log('Added queue option:', queue.queue_name, 'ID:', queue.id, 'Selected:', selected);
});
$select.html(options);
// console.log('Queue options loaded, final select value:', $select.val());
} else {
console.error('Failed to load queues:', response);
}
}).fail(function(xhr, status, error) {
console.error('Queue loading failed:', error);
});
}
// Voice management for workflow steps
window.loadWorkflowVoices = function(button) {
var $button = $(button);
var $select = $button.prev('select.voice-select');
var currentValue = $select.data('current');
window.loadWorkflowVoices = function(buttonOrSelect) {
var $button, $select;
$button.text('Loading...').prop('disabled', true);
// Check if we were passed a button or a select element
if ($(buttonOrSelect).is('button')) {
$button = $(buttonOrSelect);
$select = $button.prev('select.voice-select');
} else if ($(buttonOrSelect).is('select')) {
$select = $(buttonOrSelect);
$button = $select.next('button');
} else {
// Fallback - assume it's a button
$button = $(buttonOrSelect);
$select = $button.prev('select.voice-select');
}
// Read the current value - first check if there's a selected option with a value, then data-current attribute
var currentValue = '';
var selectedOption = $select.find('option:selected');
if (selectedOption.length && selectedOption.val()) {
currentValue = selectedOption.val();
} else {
currentValue = $select.attr('data-current') || '';
}
// console.log('loadWorkflowVoices - currentValue:', currentValue, 'from data-current:', $select.attr('data-current'));
if ($button.length) {
$button.text('Loading...').prop('disabled', true);
}
$.post(twp_ajax.ajax_url, {
action: 'twp_get_elevenlabs_voices',
nonce: twp_ajax.nonce
}, function(response) {
$button.text('Load Voices').prop('disabled', false);
// console.log('Voice loading response:', response);
if ($button.length) {
$button.text('Load Voices').prop('disabled', false);
}
if (response.success) {
var options = '<option value="">Default voice</option>';
response.data.forEach(function(voice) {
var selected = voice.voice_id === currentValue ? ' selected' : '';
var selected = (voice.voice_id === currentValue) ? ' selected' : '';
var description = voice.labels ? Object.values(voice.labels).join(', ') : '';
var optionText = voice.name + (description ? ' (' + description + ')' : '');
options += '<option value="' + voice.voice_id + '"' + selected + '>' + optionText + '</option>';
options += '<option value="' + voice.voice_id + '" data-voice-name="' + voice.name + '"' + selected + '>' + optionText + '</option>';
if (selected) {
// console.log('Setting voice as selected:', voice.name, 'ID:', voice.voice_id);
}
});
$select.html(options);
// If we had a current value, make sure it's selected
if (currentValue) {
$select.val(currentValue);
// Update the voice name field with the selected voice's name
var $voiceNameInput = $select.siblings('input[name="voice_name"]');
if ($voiceNameInput.length) {
var selectedVoice = $select.find('option:selected');
var voiceName = selectedVoice.data('voice-name') || selectedVoice.text() || '';
if (selectedVoice.val() === '') {
voiceName = '';
}
$voiceNameInput.val(voiceName);
}
}
// console.log('Voice loaded and set to:', currentValue, '- Final select value:', $select.val());
} else {
var errorMessage = 'Error loading voices: ';
if (typeof response.data === 'string') {
@@ -1552,7 +1699,9 @@ jQuery(document).ready(function($) {
alert(errorMessage);
}
}).fail(function() {
$button.text('Load Voices').prop('disabled', false);
if ($button.length) {
$button.text('Load Voices').prop('disabled', false);
}
alert('Failed to load voices. Please check your API key.');
});
};
@@ -1587,22 +1736,40 @@ jQuery(document).ready(function($) {
}
});
// Handle voice selection changes to update hidden voice_name field
$(document).on('change', 'select.voice-select', function() {
var $select = $(this);
var $voiceNameInput = $select.siblings('input[name="voice_name"]');
var selectedOption = $select.find('option:selected');
var voiceName = selectedOption.data('voice-name') || selectedOption.text() || '';
// If it's the default option, clear the name
if (selectedOption.val() === '') {
voiceName = '';
}
if ($voiceNameInput.length) {
$voiceNameInput.val(voiceName);
// console.log('Voice name updated to:', voiceName);
}
});
// Handle IVR action changes to show/hide appropriate target inputs
$(document).on('change', '.ivr-action-select', function() {
var $option = $(this).closest('.ivr-option');
var $container = $option.find('.ivr-target-container');
var action = $(this).val();
// Hide all target inputs
$container.find('.target-forward, .target-queue, .target-voicemail, .target-message').hide();
// Hide and disable all target inputs first
$container.find('.target-forward, .target-queue, .target-voicemail, .target-message').hide().prop('disabled', true);
// Show the appropriate input based on action
// Show and enable the appropriate input based on action
switch(action) {
case 'forward':
$container.find('.target-forward').show();
$container.find('.target-forward').show().prop('disabled', false);
break;
case 'queue':
$container.find('.target-queue').show();
$container.find('.target-queue').show().prop('disabled', false);
// Load queues if not already loaded
var $queueSelect = $container.find('.target-queue');
if ($queueSelect.find('option').length <= 1) {
@@ -1610,10 +1777,10 @@ jQuery(document).ready(function($) {
}
break;
case 'voicemail':
$container.find('.target-voicemail').show();
$container.find('.target-voicemail').show().prop('disabled', false);
break;
case 'message':
$container.find('.target-message').show();
$container.find('.target-message').show().prop('disabled', false);
break;
}
});
@@ -1672,7 +1839,7 @@ jQuery(document).ready(function($) {
// Play after loading
audio.play().catch(function(error) {
console.log('Audio play error:', error);
// console.log('Audio play error:', error);
// If data URL fails, try direct Twilio URL as fallback
if (voicemail.recording_url) {
audio.src = voicemail.recording_url + '.mp3';