';
// console.log('Schedule ID being set:', (data.schedule_id || ''));
html += '
';
html += '
';
html += '
After-Hours Actions
';
html += '
Define what happens when calls come in outside business hours:
';
html += '
';
html += '
';
// 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');
data.after_hours_steps.forEach(function(step, index) {
// console.log('Generating HTML for after-hours step', index, ':', step);
html += generateAfterHoursStepHtml(step, index);
});
} else {
// console.log('No after-hours steps found');
html += '
No after-hours steps configured. Add steps below.
';
}
html += '
';
html += '
';
html += '';
html += '';
html += '';
html += '
';
html += '
';
html += '
';
// Load schedules after form is rendered
html += '';
break;
case 'sms':
html += '
';
html += '
SMS Notification
';
html += '';
html += '';
html += '';
html += '';
html += '
Use {from}, {to}, {time} as placeholders
';
html += '
';
break;
}
return html;
}
function generateIvrOptionHtml(digit, option) {
var html = '
';
html += '';
html += '';
html += '';
// Target input - varies based on action type
html += '
';
// Forward action - phone number input
html += '';
// Queue action - queue dropdown
var queueCurrent = '';
if (option.action === 'queue') {
queueCurrent = option.queue_id || option.target || option.number || '';
}
html += '';
// Voicemail action - message input
html += '';
// Message action - message input
html += '';
html += '
';
html += '';
html += '
';
return html;
}
function generateAfterHoursStepHtml(step, index) {
var html = '
';
html += '
';
html += '' + (index + 1) + '.';
html += '' + getStepTypeName(step.type) + '';
html += '';
html += '
';
html += '
';
switch(step.type) {
case 'greeting':
html += '';
break;
case 'forward':
html += '';
break;
case 'voicemail':
html += '';
break;
case 'queue':
html += '';
break;
case 'sms':
html += '';
html += '';
break;
}
html += '';
html += '
';
html += '
';
return html;
}
window.addAfterHoursStep = function() {
var stepType = $('#after-hours-step-type').val();
if (!stepType) {
alert('Please select a step type');
return;
}
// Remove the "no steps" message if it exists
$('.no-steps-message').remove();
var stepList = $('.after-hours-step-list');
var currentSteps = stepList.find('.after-hours-step').length;
var newStep = {
type: stepType,
message: '',
number: '',
greeting: '',
queue_name: '',
to_number: ''
};
stepList.append(generateAfterHoursStepHtml(newStep, currentSteps));
$('#after-hours-step-type').val('');
};
window.removeAfterHoursStep = function(index) {
$('.after-hours-step[data-index="' + index + '"]').remove();
// Reindex remaining steps
$('.after-hours-step').each(function(i) {
$(this).attr('data-index', i);
$(this).find('.step-number').text((i + 1) + '.');
$(this).find('input, textarea').each(function() {
var name = $(this).attr('name');
if (name) {
name = name.replace(/\[\d+\]/, '[' + i + ']');
$(this).attr('name', name);
}
});
$(this).find('.remove-step').attr('onclick', 'removeAfterHoursStep(' + i + ')');
});
if ($('.after-hours-step').length === 0) {
$('.after-hours-step-list').html('
No after-hours steps configured. Add steps below.
');
}
};
window.loadSchedulesForStep = function() {
// 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);
if (response.success) {
var $select = $('#schedule-select');
var currentScheduleId = $select.data('current') || $select.val();
// console.log('Current schedule ID to select:', currentScheduleId);
var options = '';
response.data.forEach(function(schedule) {
var selected = (schedule.id == currentScheduleId) ? ' selected' : '';
options += '';
// console.log('Added schedule option:', schedule.schedule_name, 'ID:', schedule.id, 'Selected:', selected);
});
$select.html(options);
// Ensure the current value is selected after DOM update
setTimeout(function() {
if (currentScheduleId) {
$select.val(currentScheduleId);
// 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');
}
}, 10);
} else {
console.error('Failed to load schedules:', response);
$('#schedule-select').html('');
}
}).fail(function(xhr, status, error) {
console.error('AJAX error loading schedules:', error);
$('#schedule-select').html('');
});
};
window.addIvrOption = function() {
var nextDigit = $('#ivr-options-list .ivr-option').length + 1;
var newOptionHtml = generateIvrOptionHtml(nextDigit.toString(), { action: 'forward', number: '' });
$('#ivr-options-list').append(newOptionHtml);
};
window.removeIvrOption = function(button) {
$(button).closest('.ivr-option').remove();
};
// Save step configuration
$('#save-step-btn').on('click', function() {
var stepId = parseInt($('#step-id').val());
var stepType = $('#step-type').val();
var formData = $('#step-config-form').serializeArray();
var step = workflowSteps.find(function(s) { return s.id === stepId; });
if (!step) return;
// Parse form data into step data
step.data = parseStepFormData(stepType, formData);
// console.log('Saved step data:', step);
if (stepType === 'schedule_check') {
// console.log('Saved schedule step data:', step.data);
}
updateWorkflowDisplay();
closeStepConfigModal();
});
function parseStepFormData(stepType, formData) {
var data = {};
// console.log('Parsing form data for step type:', stepType);
formData.forEach(function(field) {
// console.log('Processing field:', field.name, '=', field.value);
if (field.name === 'use_tts') {
data.use_tts = true;
} else if (field.name === 'audio_type') {
data.audio_type = field.value;
} else if (field.name === 'audio_url') {
data.audio_url = field.value;
} else if (field.name === 'voice_id') {
data.voice_id = field.value;
} else if (field.name.endsWith('[]')) {
var key = field.name.replace('[]', '');
if (!data[key]) data[key] = [];
data[key].push(field.value);
} else {
data[field.name] = field.value;
}
});
// 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) {
var selectedOption = $('#step-config-form select[name="queue_id"] option:selected');
if (selectedOption.length) {
data.queue_name = selectedOption.text();
}
}
// For schedule steps, also save the schedule name for display purposes
if (stepType === 'schedule_check' && data.schedule_id) {
var selectedOption = $('#step-config-form select[name="schedule_id"] option:selected');
if (selectedOption.length) {
data.schedule_name = selectedOption.text();
}
}
// 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++) {
// Get the appropriate target value based on action type
var targetValue = data.target[i];
var option = {
action: data.action[i],
description: data.description[i],
number: '',
queue_name: '',
message: ''
};
// Set the appropriate field based on action type
switch(data.action[i]) {
case 'forward':
option.number = targetValue;
break;
case 'queue':
option.queue_name = targetValue;
break;
case 'voicemail':
option.message = targetValue;
break;
case 'message':
option.message = targetValue;
break;
}
// 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;
delete data.description;
delete data.target;
}
// Handle schedule check after-hours steps
if (stepType === 'schedule_check') {
// console.log('Parsing schedule_check step data:', data);
var afterHoursSteps = [];
// First, remove any after_hours_steps fields from the main data object
var fieldsToRemove = [];
for (var key in data) {
if (key.startsWith('after_hours_steps[')) {
fieldsToRemove.push(key);
}
}
fieldsToRemove.forEach(function(key) {
delete data[key];
});
// Find all after_hours_steps fields
formData.forEach(function(field) {
var match = field.name.match(/after_hours_steps\[(\d+)\]\[(\w+)\]/);
if (match) {
var index = parseInt(match[1]);
var key = match[2];
if (!afterHoursSteps[index]) {
afterHoursSteps[index] = {};
}
afterHoursSteps[index][key] = field.value;
}
});
// Filter out empty entries and reassign
data.after_hours_steps = afterHoursSteps.filter(function(step) {
return step && step.type;
});
// console.log('Parsed schedule_check data:', data);
}
return data;
}
window.removeWorkflowStep = function(stepId) {
workflowSteps = workflowSteps.filter(function(step) {
return step.id !== stepId;
});
updateWorkflowDisplay();
};
window.editWorkflowStep = function(stepId) {
var step = workflowSteps.find(function(s) { return s.id === stepId; });
if (step) {
openStepConfigModal(stepId, step.type);
}
};
function updateWorkflowDisplay() {
var stepsHtml = '';
workflowSteps.forEach(function(step, index) {
stepsHtml += '
Capabilities:';
var capabilities = [];
if (number.capabilities.voice) capabilities.push('Voice');
if (number.capabilities.sms) capabilities.push('SMS');
if (number.capabilities.mms) capabilities.push('MMS');
html += capabilities.join(', ') + '
';
html += '
';
html += '
';
html += '';
html += '';
html += '
';
html += '
';
});
html += '
';
$('#twp-numbers-list').html(html);
}
function displayAvailableNumbers(numbers) {
if (numbers.length === 0) {
$('#search-results').html('
No numbers found matching your criteria. Try different search terms.
');
return;
}
var html = '';
numbers.forEach(function(number) {
html += '
';
html += '
';
html += '
' + number.phone_number + '
';
html += '
';
var capabilities = [];
if (number.capabilities.voice) capabilities.push('Voice');
if (number.capabilities.sms) capabilities.push('SMS');
if (number.capabilities.mms) capabilities.push('MMS');
html += capabilities.join(', ');
html += '
';
html += '
';
html += '
$1.00/month
';
html += '';
html += '
';
});
$('#search-results').html(html);
}
window.purchaseNumber = function(phoneNumber) {
if (confirm('Purchase ' + phoneNumber + ' for $1.00/month?')) {
$.post(twp_ajax.ajax_url, {
action: 'twp_purchase_number',
phone_number: phoneNumber,
voice_url: twp_ajax.rest_url + 'twilio-webhook/v1/voice',
sms_url: twp_ajax.rest_url + 'twilio-webhook/v1/sms',
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
alert('Phone number purchased successfully!');
refreshNumbers();
$('#twp-available-numbers').hide();
} else {
alert('Error purchasing number: ' + response.error);
}
});
}
};
window.configureNumber = function(numberSid, phoneNumber) {
$('#number-sid').val(numberSid);
$('#phone-number').val(phoneNumber);
tb_show('Configure: ' + phoneNumber, '#TB_inline?inlineId=number-config-modal&width=600&height=400');
};
window.closeNumberConfigModal = function() {
tb_remove();
};
$('#number-config-form').on('submit', function(e) {
e.preventDefault();
var formData = $(this).serialize();
formData += '&action=twp_configure_number&nonce=' + twp_ajax.nonce;
$.post(twp_ajax.ajax_url, formData, function(response) {
if (response.success) {
alert('Phone number configured successfully!');
closeNumberConfigModal();
refreshNumbers();
} else {
alert('Error configuring number: ' + response.error);
}
});
});
window.releaseNumber = function(numberSid, phoneNumber) {
if (confirm('Are you sure you want to release ' + phoneNumber + '? This action cannot be undone and you will lose this phone number.')) {
$.post(twp_ajax.ajax_url, {
action: 'twp_release_number',
number_sid: numberSid,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
alert('Phone number released successfully!');
refreshNumbers();
} else {
alert('Error releasing number: ' + response.error);
}
});
}
};
// Initialize phone numbers if on that page
if ($('#twp-numbers-list').length) {
refreshNumbers();
}
// Queue management for workflow steps
window.loadQueues = function(button) {
var $button = $(button);
var $select = $button.prev('select.queue-select');
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, {
action: 'twp_get_all_queues',
nonce: twp_ajax.nonce
}, function(response) {
$button.text('Load Queues').prop('disabled', false);
if (response.success) {
var options = '';
response.data.forEach(function(queue) {
var selected = queue.id == currentValue ? ' selected' : '';
options += '';
});
$select.html(options);
} else {
alert('Error loading queues: ' + (response.data || 'Unknown error'));
}
}).fail(function() {
$button.text('Load Queues').prop('disabled', false);
alert('Failed to load queues');
});
};
// Load queues for a specific select element (used in IVR options)
function loadQueuesForSelect($select) {
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 = '';
response.data.forEach(function(queue) {
var selected = queue.id == currentValue ? ' selected' : '';
options += '';
// 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(buttonOrSelect) {
var $button, $select;
// 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) {
// console.log('Voice loading response:', response);
if ($button.length) {
$button.text('Load Voices').prop('disabled', false);
}
if (response.success) {
var options = '';
response.data.forEach(function(voice) {
var selected = (voice.voice_id === currentValue) ? ' selected' : '';
var description = voice.labels ? Object.values(voice.labels).join(', ') : '';
var optionText = voice.name + (description ? ' (' + description + ')' : '');
options += '';
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') {
errorMessage += response.data;
} else if (response.data && response.data.detail) {
errorMessage += response.data.detail;
} else if (response.data && response.data.error) {
errorMessage += response.data.error;
} else {
errorMessage += 'Unknown error occurred';
}
alert(errorMessage);
}
}).fail(function() {
if ($button.length) {
$button.text('Load Voices').prop('disabled', false);
}
alert('Failed to load voices. Please check your API key.');
});
};
// Toggle audio type options visibility
$(document).on('change', 'input[name="audio_type"]', function() {
var $container = $(this).closest('.step-config-section');
var $ttsOptions = $container.find('.tts-options');
var $audioOptions = $container.find('.audio-options');
var audioType = $(this).val();
// Hide all options first
$ttsOptions.hide();
$audioOptions.hide();
// Show the appropriate options based on selection
if (audioType === 'tts') {
$ttsOptions.show();
// Auto-load voices if they haven't been loaded yet
var $voiceSelect = $ttsOptions.find('.voice-select');
if ($voiceSelect.length && $voiceSelect.find('option').length <= 1) {
// Check if API key exists before auto-loading
if (twp_ajax.has_elevenlabs_key) {
loadWorkflowVoices($voiceSelect[0]);
}
}
} else if (audioType === 'audio') {
$audioOptions.show();
}
// 'say' type doesn't need additional options
});
// Legacy support for old use_tts checkbox (in case old workflows exist)
$(document).on('change', 'input[name="use_tts"]', function() {
var $ttsOptions = $(this).closest('.step-config-section').find('.tts-options');
if ($(this).is(':checked')) {
$ttsOptions.show();
} else {
$ttsOptions.hide();
}
});
// 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 and disable all target inputs first
$container.find('.target-forward, .target-queue, .target-voicemail, .target-message').hide().prop('disabled', true);
// Show and enable the appropriate input based on action
switch(action) {
case 'forward':
$container.find('.target-forward').show().prop('disabled', false);
break;
case 'queue':
$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) {
loadQueuesForSelect($queueSelect);
}
break;
case 'voicemail':
$container.find('.target-voicemail').show().prop('disabled', false);
break;
case 'message':
$container.find('.target-message').show().prop('disabled', false);
break;
}
});
// Auto-load voices when step config modal opens if API key exists
$(document).on('click', '.step-btn', function() {
setTimeout(function() {
// Check if API key exists in main settings
if (twp_ajax.has_elevenlabs_key) {
$('.voice-select').each(function() {
if ($(this).find('option').length <= 1) {
var button = $(this).next('button');
if (button.length) {
loadWorkflowVoices(button[0]);
}
}
});
}
}, 500);
});
// Voicemail Management
window.playVoicemail = function(voicemailId, recordingUrl) {
// First load voicemail details
$.post(twp_ajax.ajax_url, {
action: 'twp_get_voicemail',
voicemail_id: voicemailId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
var voicemail = response.data;
// Update modal with voicemail details
$('#voicemail-from').text(voicemail.from_number || 'Unknown');
$('#voicemail-date').text(voicemail.created_at || '');
$('#voicemail-duration').text(voicemail.duration ? voicemail.duration + ' seconds' : 'Unknown');
$('#voicemail-player-modal').data('voicemail-id', voicemailId);
// Show modal using ThickBox
tb_show('Voicemail Player', '#TB_inline?inlineId=voicemail-player-modal&width=600&height=500');
// Now fetch the audio data
$.post(twp_ajax.ajax_url, {
action: 'twp_get_voicemail_audio',
voicemail_id: voicemailId,
nonce: twp_ajax.nonce
}, function(audioResponse) {
if (audioResponse.success) {
var audio = document.getElementById('voicemail-audio');
if (audio) {
// Use the data URL directly
audio.src = audioResponse.data.audio_url;
// Show transcription
showVoicemail(voicemailId, audioResponse.data.audio_url, voicemail.transcription);
// Play after loading
audio.play().catch(function(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';
audio.play().catch(function(e) {
alert('Unable to play audio. The recording may require authentication.');
});
}
});
}
} else {
alert('Error loading audio: ' + (audioResponse.data || 'Unknown error'));
console.error('Audio load error:', audioResponse);
}
}).fail(function(xhr, status, error) {
alert('Failed to load audio: ' + error);
console.error('AJAX error:', xhr.responseText);
});
} else {
alert('Error loading voicemail: ' + (response.data || 'Unknown error'));
}
}).fail(function() {
alert('Failed to load voicemail details');
});
};
window.viewVoicemail = function(voicemailId) {
// Just use playVoicemail without auto-play
playVoicemail(voicemailId, '');
};
function showVoicemail(voicemailId, recordingUrl, transcription) {
// Set the audio source - already set by playVoicemail
// Set transcription text
var transcriptionDiv = document.getElementById('voicemail-transcription-text');
if (transcriptionDiv) {
if (transcription && transcription !== 'Transcription pending...' && transcription !== 'Transcription failed') {
transcriptionDiv.innerHTML = '
' + transcription + '
';
// Hide the generate transcription button if we have a transcription
var transcribeBtn = document.getElementById('transcribe-btn');
if (transcribeBtn) {
transcribeBtn.style.display = 'none';
}
} else if (transcription === 'Transcription failed') {
transcriptionDiv.innerHTML = '
Transcription failed. Please try again.
';
} else {
transcriptionDiv.innerHTML = 'No transcription available.';
// Show the generate transcription button
var transcribeBtn = document.getElementById('transcribe-btn');
if (transcribeBtn) {
transcribeBtn.style.display = 'inline-block';
transcribeBtn.setAttribute('data-voicemail-id', voicemailId);
}
}
}
// Store current voicemail ID for actions
window.currentVoicemailId = voicemailId;
window.currentRecordingUrl = recordingUrl;
// Modal is already shown by playVoicemail function
}
window.closeVoicemailModal = function() {
tb_remove();
// Stop audio playback
var audio = document.getElementById('voicemail-audio');
if (audio) {
audio.pause();
audio.currentTime = 0;
}
};
window.downloadVoicemail = function() {
if (window.currentRecordingUrl) {
window.open(window.currentRecordingUrl, '_blank');
}
};
window.deleteVoicemail = function() {
if (confirm('Are you sure you want to delete this voicemail?')) {
$.post(twp_ajax.ajax_url, {
action: 'twp_delete_voicemail',
voicemail_id: window.currentVoicemailId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
closeVoicemailModal();
location.reload();
} else {
alert('Error deleting voicemail');
}
});
}
};
window.deleteVoicemailConfirm = function(voicemailId) {
if (confirm('Are you sure you want to delete this voicemail?')) {
$.post(twp_ajax.ajax_url, {
action: 'twp_delete_voicemail',
voicemail_id: voicemailId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
location.reload();
} else {
alert('Error deleting voicemail');
}
});
}
};
window.transcribeVoicemail = function() {
var voicemailId = $('#transcribe-btn').data('voicemail-id') || window.currentVoicemailId;
if (!voicemailId) {
alert('No voicemail selected');
return;
}
$('#transcribe-btn').text('Generating...').prop('disabled', true);
$.post(twp_ajax.ajax_url, {
action: 'twp_transcribe_voicemail',
voicemail_id: voicemailId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
$('#voicemail-transcription-text').html('
';
}
$('#group-members-list').html(html);
}
});
}
window.addGroupMember = function() {
var groupId = $('#current-group-id').val();
var userId = $('#add-member-select').val();
var priority = $('#add-member-priority').val() || 0;
if (!userId) {
alert('Please select a user to add');
return;
}
$.post(twp_ajax.ajax_url, {
action: 'twp_add_group_member',
group_id: groupId,
user_id: userId,
priority: priority,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
$('#add-member-select').val('');
$('#add-member-priority').val(0);
loadGroupMembers(groupId);
} else {
alert('Error adding member: ' + (response.data || 'Unknown error'));
}
});
};
window.removeGroupMember = function(userId) {
var groupId = $('#current-group-id').val();
if (confirm('Remove this member from the group?')) {
$.post(twp_ajax.ajax_url, {
action: 'twp_remove_group_member',
group_id: groupId,
user_id: userId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
loadGroupMembers(groupId);
} else {
alert('Error removing member: ' + (response.data || 'Unknown error'));
}
});
}
};
// Agent Queue Functions
window.updateAgentStatus = function(status) {
$.post(twp_ajax.ajax_url, {
action: 'twp_set_agent_status',
status: status,
nonce: twp_ajax.nonce
}, function(response) {
if (!response.success) {
alert('Error updating status: ' + (response.data || 'Unknown error'));
}
});
};
window.acceptCall = function(callId) {
var button = $('[onclick="acceptCall(' + callId + ')"]');
button.prop('disabled', true).text('Accepting...');
$.post(twp_ajax.ajax_url, {
action: 'twp_accept_call',
call_id: callId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
// Show success modal instead of basic alert
showCallAcceptedModal();
refreshWaitingCalls();
} else {
// Show error modal
showErrorModal('Error accepting call: ' + response.data);
button.prop('disabled', false).text('Accept');
}
}).fail(function() {
showErrorModal('Failed to accept call. Please try again.');
button.prop('disabled', false).text('Accept');
});
};
// Modal functions using WordPress built-in modal system
window.showCallAcceptedModal = function() {
// Create WordPress-style modal HTML
var modalHtml = `
📞 Call Accepted!
✅ Call has been assigned to you successfully.
📱 You should receive the call on your phone within the next few seconds.
🔗 The call will connect you directly to the customer.
`;
// Add modal HTML to body if not already there
if (!document.getElementById('twp-call-accepted-modal')) {
$('body').append(modalHtml);
}
// Use WordPress ThickBox
tb_show('Call Accepted', '#TB_inline?inlineId=twp-call-accepted-modal&width=400&height=250');
// Auto close after 5 seconds
setTimeout(function() {
tb_remove();
}, 5000);
};
window.showErrorModal = function(message) {
// Create WordPress-style error modal HTML
var modalHtml = `
❌ Error
${message}
`;
// Remove existing error modal
$('#twp-error-modal').remove();
// Add modal HTML to body
$('body').append(modalHtml);
// Use WordPress ThickBox
tb_show('Error', '#TB_inline?inlineId=twp-error-modal&width=400&height=200');
};
// View call details function for Call Log page
window.viewCallDetails = function(callSid) {
// Fetch call details via AJAX
$.post(twp_ajax.ajax_url, {
action: 'twp_get_call_details',
call_sid: callSid,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
var call = response.data;
// Build detailed view HTML
var detailsHtml = `
`;
// Show in WordPress modal
showCallDetailsModal(detailsHtml);
} else {
showErrorModal('Failed to load call details: ' + (response.data || 'Unknown error'));
}
}).fail(function() {
showErrorModal('Failed to load call details. Please try again.');
});
};
// Show call details modal
function showCallDetailsModal(content) {
// Remove existing modal if present
$('#call-details-modal').remove();
// Create WordPress-style modal HTML
var modalHtml = `
📞 Call Details
${content}
`;
// Add modal HTML to body
$('body').append(modalHtml);
// Use WordPress ThickBox
tb_show('Call Details', '#TB_inline?inlineId=call-details-modal&width=700&height=500');
}
window.refreshWaitingCalls = function() {
if (!$('#waiting-calls-list').length) return;
$.post(twp_ajax.ajax_url, {
action: 'twp_get_waiting_calls',
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
var html = '';
if (response.data.length === 0) {
html = '
No calls waiting
';
} else {
response.data.forEach(function(call) {
var waitMinutes = Math.floor(call.wait_seconds / 60);
var waitSeconds = call.wait_seconds % 60;
var waitTime = waitMinutes > 0 ? waitMinutes + 'm ' + waitSeconds + 's' : waitSeconds + 's';
html += '
';
html += '
' + call.position + '
';
html += '
' + call.queue_name + '
';
html += '
' + call.from_number + '
';
html += '
' + waitTime + '
';
html += '
';
html += '
';
});
}
$('#waiting-calls-list').html(html);
}
});
};
// Auto-refresh waiting calls every 5 seconds on agent queue page
if ($('#waiting-calls-list').length) {
setInterval(refreshWaitingCalls, 5000);
refreshWaitingCalls(); // Initial load
}
// Click-to-Call Functions
window.initiateCall = function() {
var toNumber = prompt('Enter number to call (e.g., +1234567890):');
if (toNumber) {
$.post(twp_ajax.ajax_url, {
action: 'twp_initiate_outbound_call',
to_number: toNumber,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
alert('Call initiated! You should receive a call on your phone shortly, then the call will connect to ' + toNumber);
} else {
alert('Error initiating call: ' + (response.data || 'Unknown error'));
}
});
}
};
// Phone Number Management for Workflows
$(document).on('click', '.add-phone-number', function() {
var phoneNumbers = [];
var $container = $('#workflow-phone-numbers');
// Get available phone numbers from first select
var $firstSelect = $container.find('select').first();
var availableOptions = $firstSelect.html();
var newRow = '
' +
'' +
'' +
'
';
$container.append(newRow);
// Update button text on first row
$container.find('.add-phone-number').first().text('Add Another Number');
});
$(document).on('click', '.remove-phone-number', function() {
var $container = $('#workflow-phone-numbers');
$(this).closest('.phone-number-row').remove();
// Update button text if only one row remains
if ($container.find('.phone-number-row').length === 1) {
$container.find('.add-phone-number').first().text('Add Number');
}
});
// Callback Management Functions
window.requestCallback = function() {
var phoneNumber = prompt('Enter phone number for callback (e.g., +1234567890):');
if (phoneNumber) {
$.post(twp_ajax.ajax_url, {
action: 'twp_request_callback',
phone_number: phoneNumber,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
alert('Callback requested successfully! The customer will be called back soon.');
refreshCallbacks();
} else {
alert('Error requesting callback: ' + (response.data.message || 'Unknown error'));
}
});
}
};
window.refreshCallbacks = function() {
if (!$('#callbacks-list').length) return;
$.post(twp_ajax.ajax_url, {
action: 'twp_get_callbacks',
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
var html = '';
var callbacks = response.data.callbacks;
var stats = response.data.stats;
if (callbacks.length === 0) {
html = '
No pending callbacks
';
} else {
callbacks.forEach(function(callback) {
var statusClass = 'status-' + callback.status;
var queueName = callback.queue_name || 'Direct';
html += '
';
html += '
' + callback.phone_number + '
';
html += '
' + queueName + '
';
html += '
' + callback.requested_at + '
';
html += '
' + callback.wait_minutes + ' min
';
html += '
' + callback.status + '
';
html += '
' + callback.attempts + '
';
html += '
';
});
}
$('#callbacks-list').html(html);
// Update stats if available
if (stats) {
$('#callback-stats-total').text(stats.total_requests);
$('#callback-stats-completed').text(stats.completed);
$('#callback-stats-pending').text(stats.pending);
$('#callback-stats-success-rate').text(stats.success_rate + '%');
if (stats.avg_completion_time) {
$('#callback-stats-avg-time').text(Math.round(stats.avg_completion_time) + ' min');
}
}
}
});
};
// Auto-refresh callbacks every 10 seconds on callbacks page
if ($('#callbacks-list').length) {
setInterval(refreshCallbacks, 10000);
refreshCallbacks(); // Initial load
}
// Initialize on load
updateDashboardStats();
});