jQuery(document).ready(function($) { // Schedule Management window.openScheduleModal = function() { $('#schedule-form')[0].reset(); $('#schedule-id').val(''); $('#schedule-modal-title').text('Add New Schedule'); // Reset form fields to defaults $('[name="days_of_week[]"]').prop('checked', false); $('[name="is_active"]').prop('checked', true); $('#after-hours-forward').hide(); $('#after-hours-workflow').hide(); tb_show('Add New Schedule', '#TB_inline?inlineId=schedule-modal&width=650&height=600'); }; window.closeScheduleModal = function() { tb_remove(); }; window.editSchedule = function(id) { // Load schedule data and populate form $.post(twp_ajax.ajax_url, { action: 'twp_get_schedule', schedule_id: id, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var schedule = response.data; $('#schedule-modal-title').text('Edit Schedule'); $('#schedule-id').val(schedule.id); $('[name="schedule_name"]').val(schedule.schedule_name); $('[name="start_time"]').val(schedule.start_time); $('[name="end_time"]').val(schedule.end_time); $('[name="workflow_id"]').val(schedule.workflow_id); $('[name="holiday_dates"]').val(schedule.holiday_dates || ''); $('[name="is_active"]').prop('checked', schedule.is_active == '1'); // Set days of week checkboxes var days = schedule.days_of_week ? schedule.days_of_week.split(',') : []; $('[name="days_of_week[]"]').prop('checked', false); days.forEach(function(day) { $('[name="days_of_week[]"][value="' + day.trim() + '"]').prop('checked', true); }); // Set after hours action if (schedule.after_hours_action) { $('[name="after_hours_action"]').val(schedule.after_hours_action); toggleAfterHoursFields($('[name="after_hours_action"]')[0]); if (schedule.after_hours_action === 'forward' && schedule.after_hours_forward_number) { $('[name="after_hours_forward_number"]').val(schedule.after_hours_forward_number); } else if (schedule.after_hours_action === 'workflow' && schedule.after_hours_workflow_id) { $('[name="after_hours_workflow_id"]').val(schedule.after_hours_workflow_id); } } else if (schedule.forward_number) { // Legacy support for old forward_number field $('[name="after_hours_action"]').val('forward'); $('[name="after_hours_forward_number"]').val(schedule.forward_number); toggleAfterHoursFields($('[name="after_hours_action"]')[0]); } else { $('[name="after_hours_action"]').val('workflow'); toggleAfterHoursFields($('[name="after_hours_action"]')[0]); } tb_show('Edit Schedule: ' + schedule.schedule_name, '#TB_inline?inlineId=schedule-modal&width=650&height=600'); } else { alert('Error loading schedule data'); } }); }; window.deleteSchedule = function(id) { if (confirm('Are you sure you want to delete this schedule?')) { $.post(twp_ajax.ajax_url, { action: 'twp_delete_schedule', schedule_id: id, nonce: twp_ajax.nonce }, function(response) { if (response.success) { location.reload(); } }); } }; $('#schedule-form').on('submit', function(e) { e.preventDefault(); // Get form data excluding days_of_week (we'll handle manually to avoid duplicates) var formData = $(this).serializeArray(); var filteredData = []; // Filter out days_of_week from serialized data to avoid duplicates formData.forEach(function(item) { if (item.name !== 'days_of_week[]') { filteredData.push(item.name + '=' + encodeURIComponent(item.value)); } }); var formDataString = filteredData.join('&'); // Collect days of week checkboxes manually var daysOfWeek = []; $('[name="days_of_week[]"]:checked').each(function() { daysOfWeek.push($(this).val()); }); // Add days to form data if any selected if (daysOfWeek.length > 0) { formDataString += '&days_of_week[]=' + daysOfWeek.join('&days_of_week[]='); } // Add after-hours fields var afterHoursAction = $('select[name="after_hours_action"]').val(); if (afterHoursAction) { formDataString += '&after_hours_action=' + encodeURIComponent(afterHoursAction); if (afterHoursAction === 'workflow') { var afterHoursWorkflow = $('select[name="after_hours_workflow_id"]').val(); if (afterHoursWorkflow) { formDataString += '&after_hours_workflow_id=' + encodeURIComponent(afterHoursWorkflow); } } else if (afterHoursAction === 'forward') { var afterHoursForward = $('input[name="after_hours_forward_number"]').val(); if (afterHoursForward) { formDataString += '&after_hours_forward_number=' + encodeURIComponent(afterHoursForward); } } } formDataString += '&action=twp_save_schedule&nonce=' + twp_ajax.nonce; // console.log('Submitting schedule form data:', formDataString); $.post(twp_ajax.ajax_url, formDataString, function(response) { // console.log('Schedule save response:', response); if (response.success) { closeScheduleModal(); location.reload(); } else { alert('Error saving schedule: ' + (response.data || 'Unknown error')); } }).fail(function(xhr, status, error) { console.error('Schedule save failed:', xhr, status, error); alert('Network error saving schedule: ' + error); }); }); // Toggle after hours fields window.toggleAfterHoursFields = function(select) { var value = $(select).val(); $('#after-hours-forward').hide(); $('#after-hours-workflow').hide(); if (value === 'forward') { $('#after-hours-forward').show(); } else if (value === 'workflow') { $('#after-hours-workflow').show(); } }; window.toggleActionFields = function(select) { if ($(select).val() === 'forward') { $('#forward-fields').show(); $('#workflow-fields').hide(); } else { $('#forward-fields').hide(); $('#workflow-fields').show(); } }; // Workflow Builder var workflowSteps = []; var currentWorkflowId = null; window.openWorkflowBuilder = function() { $('#workflow-modal-title').text('Create New Workflow'); workflowSteps = []; currentWorkflowId = null; $('#workflow-basic-info')[0].reset(); loadPhoneNumbers(); updateWorkflowDisplay(); tb_show('Create New Workflow', '#TB_inline?inlineId=workflow-builder&width=900&height=700'); }; window.closeWorkflowBuilder = function() { tb_remove(); }; window.closeStepConfigModal = function() { // Hide the step config modal and remove show class $('#step-config-modal').hide().removeClass('show'); }; function loadPhoneNumbers(callback) { $.post(twp_ajax.ajax_url, { action: 'twp_get_phone_numbers', nonce: twp_ajax.nonce }, function(response) { if (response.success) { var options = ''; response.data.forEach(function(number) { options += ''; }); $('#workflow-phone').html(options); // Call the callback if provided if (typeof callback === 'function') { callback(); } } }); } // Step type button handlers $(document).on('click', '.step-btn', function() { var stepType = $(this).data('step-type'); addWorkflowStep(stepType); }); function addWorkflowStep(stepType) { var step = { id: Date.now(), type: stepType, data: getDefaultStepData(stepType) }; workflowSteps.push(step); updateWorkflowDisplay(); // Open configuration modal openStepConfigModal(step.id, stepType); } function getDefaultStepData(stepType) { switch(stepType) { case 'greeting': return { message: '', use_tts: true }; case 'ivr_menu': return { message: '', options: {}, num_digits: 1, timeout: 10 }; case 'forward': return { forward_number: '', timeout: 30 }; case 'queue': return { queue_id: '', announce_message: '' }; case 'voicemail': return { greeting_message: '', max_length: 120 }; case 'schedule_check': return { schedule_id: '', after_hours_steps: [] }; case 'sms': return { to_number: '', message: '' }; default: return {}; } } function openStepConfigModal(stepId, stepType) { 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); $('#step-id').val(stepId); $('#step-type').val(stepType); $('#step-config-title').text('Configure ' + getStepTypeName(stepType) + ' Step'); var configContent = generateStepConfigForm(stepType, step.data || {}); $('#step-config-content').html(configContent); // Move the modal outside of ThickBox if needed if ($('#step-config-modal').closest('#TB_window').length > 0) { $('#step-config-modal').appendTo('body'); } // 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); setTimeout(function() { // console.log('About to load schedules, current select element:', $('#schedule-select')); loadSchedulesForStep(); }, 100); } // If it's a queue step, load the queues if (stepType === 'queue') { setTimeout(function() { var $queueSelect = $('#step-config-modal .queue-select'); if ($queueSelect.length) { loadQueuesForSelect($queueSelect); } }, 100); } // 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); var currentValue = $select.data('current'); // console.log('Loading queue for select with current value:', currentValue); loadQueuesForSelect($select); }); // 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); } } function getStepTypeName(stepType) { var names = { 'greeting': 'Greeting', 'ivr_menu': 'IVR Menu', 'forward': 'Forward Call', 'queue': 'Call Queue', 'voicemail': 'Voicemail', 'schedule_check': 'Schedule Check', 'sms': 'SMS Notification' }; return names[stepType] || stepType; } function generateStepConfigForm(stepType, data) { var html = ''; switch(stepType) { case 'greeting': html += '
'; html += '

Greeting Message

'; html += ''; html += ''; // Audio playback options html += '
'; html += '

Audio Options

'; html += '
'; html += '
'; html += ''; // TTS Options html += '
'; html += ''; html += ''; html += ''; html += ''; html += '
'; // Audio File Options html += '
'; html += ''; html += ''; html += '

Enter the direct URL to an MP3 file. The file must be publicly accessible.

'; html += '
'; html += '
'; html += '
'; break; case 'ivr_menu': html += '
'; html += '

Menu Settings

'; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; // Audio playback options html += '
'; html += '

Audio Options

'; html += '
'; html += '
'; html += ''; // TTS Options html += '
'; html += ''; html += ''; html += ''; html += ''; html += '
'; // Audio File Options html += '
'; html += ''; html += ''; html += '

Enter the direct URL to an MP3 file. The file must be publicly accessible.

'; html += '
'; html += '
'; html += '
'; html += '
'; html += '

Menu Options

'; html += '
'; if (data.options && Object.keys(data.options).length > 0) { Object.keys(data.options).forEach(function(digit) { html += generateIvrOptionHtml(digit, data.options[digit]); }); } else { html += generateIvrOptionHtml('1', { action: 'forward', number: '' }); } html += '
'; html += '
+ Add Option
'; html += '
'; break; case 'forward': html += '
'; html += '

Forward Settings

'; html += ''; html += ''; html += ''; html += ''; html += '
'; break; case 'queue': html += '
'; html += '

Queue Settings

'; html += ''; html += ''; html += ''; html += ''; html += ''; // Audio playback options html += '
'; html += '

Audio Options

'; html += '
'; html += '
'; html += ''; // TTS Options html += '
'; html += ''; html += ''; html += ''; html += ''; html += '
'; // Audio File Options html += '
'; html += ''; html += ''; html += '

Enter the direct URL to an MP3 file. The file must be publicly accessible.

'; html += '
'; html += '
'; html += '
'; break; case 'voicemail': html += '
'; html += '

Voicemail Settings

'; html += ''; html += ''; html += ''; html += ''; // Audio playback options html += '
'; html += '

Audio Options

'; html += '
'; html += '
'; html += ''; // TTS Options html += '
'; html += ''; html += ''; html += ''; html += ''; html += '
'; // Audio File Options html += '
'; html += ''; html += ''; html += '

Enter the direct URL to an MP3 file. The file must be publicly accessible.

'; html += '
'; html += '
'; html += '
'; break; case 'schedule_check': // console.log('Generating schedule_check form with data:', data); html += '
'; html += '

Schedule Check Settings

'; html += ''; html += ''; html += '

Uses WordPress timezone: ' + twp_ajax.timezone + '

'; // 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++) { 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; 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 += '
'; stepsHtml += '
'; stepsHtml += '
'; stepsHtml += '' + (index + 1) + ''; stepsHtml += getStepTypeName(step.type); stepsHtml += '
'; stepsHtml += '
'; stepsHtml += ''; stepsHtml += ''; stepsHtml += '
'; stepsHtml += '
'; var description = getStepDescription(step); if (description) { stepsHtml += '
' + description + '
'; } stepsHtml += '
'; }); $('#workflow-steps-list').html(stepsHtml); // Update preview updateWorkflowPreview(); } function updateWorkflowPreview() { var previewHtml = ''; workflowSteps.forEach(function(step, index) { previewHtml += '
'; previewHtml += '' + (index + 1) + '. ' + getStepTypeName(step.type) + '
'; previewHtml += '' + getStepDescription(step) + ''; previewHtml += '
'; }); $('#flow-steps').html(previewHtml); } function getStepDescription(step) { switch(step.type) { case 'greeting': return step.data.message ? '"' + step.data.message.substring(0, 50) + '..."' : 'No message set'; case 'ivr_menu': var optionCount = step.data.options ? Object.keys(step.data.options).length : 0; return 'Menu with ' + optionCount + ' options'; case 'forward': return step.data.forward_number ? 'Forward to ' + step.data.forward_number : 'No number set'; case 'queue': // Display the queue name if available, otherwise show ID if (step.data.queue_name) { return 'Add to queue: ' + step.data.queue_name; } else if (step.data.queue_id) { return 'Add to queue (ID: ' + step.data.queue_id + ')'; } else { return 'No queue selected'; } case 'voicemail': return 'Record voicemail (max ' + (step.data.max_length || 120) + 's)'; case 'schedule_check': var scheduleInfo = 'No schedule selected'; if (step.data.schedule_id) { var scheduleName = step.data.schedule_name || ('Schedule ID: ' + step.data.schedule_id); scheduleInfo = 'Schedule: ' + scheduleName; } var afterHoursCount = step.data.after_hours_steps ? step.data.after_hours_steps.length : 0; return scheduleInfo + (afterHoursCount > 0 ? ' (' + afterHoursCount + ' after-hours steps)' : ''); case 'sms': return step.data.to_number ? 'Send SMS to ' + step.data.to_number : 'No recipient set'; default: return ''; } } // Save workflow $('#save-workflow-btn').on('click', function() { var formData = $('#workflow-basic-info').serializeArray(); var workflowData = {}; formData.forEach(function(field) { if (field.name === 'is_active') { workflowData.is_active = true; } else { workflowData[field.name] = field.value; } }); if (!workflowData.workflow_name) { alert('Please enter a workflow name'); return; } if (!workflowData.phone_number) { alert('Please select a phone number'); return; } if (workflowSteps.length === 0) { alert('Please add at least one step to the workflow'); return; } var payload = { action: currentWorkflowId ? 'twp_update_workflow' : 'twp_save_workflow', workflow_name: workflowData.workflow_name, phone_number: workflowData.phone_number, workflow_data: JSON.stringify({ steps: workflowSteps, conditions: [], actions: [] }), is_active: workflowData.is_active ? 1 : 0, nonce: twp_ajax.nonce }; if (currentWorkflowId) { payload.workflow_id = currentWorkflowId; } $.post(twp_ajax.ajax_url, payload, function(response) { if (response.success) { closeWorkflowBuilder(); location.reload(); } else { alert('Error saving workflow: ' + (response.data || 'Unknown error')); } }); }); window.editWorkflow = function(workflowId) { // Load workflow data and open builder $.post(twp_ajax.ajax_url, { action: 'twp_get_workflow', workflow_id: workflowId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var workflow = response.data; $('#workflow-modal-title').text('Edit Workflow: ' + workflow.workflow_name); tb_show('Edit Workflow: ' + workflow.workflow_name, '#TB_inline?inlineId=workflow-builder&width=900&height=700'); // Set basic info $('#workflow-basic-info')[0].reset(); $('[name="workflow_name"]').val(workflow.workflow_name); $('[name="is_active"]').prop('checked', workflow.is_active == '1'); // Store the phone number to select after options are loaded var phoneNumberToSelect = workflow.phone_number; // Load workflow data currentWorkflowId = workflowId; // 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); // Debug schedule steps specifically workflowSteps.forEach(function(step, index) { if (step.type === 'schedule_check') { // 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); workflowSteps = []; } } else { // console.log('No workflow data found'); workflowSteps = []; } // Load phone numbers and select the saved one loadPhoneNumbers(function() { $('#workflow-phone').val(phoneNumberToSelect); // Trigger change event in case there are any listeners $('#workflow-phone').trigger('change'); }); updateWorkflowDisplay(); } else { alert('Error loading workflow: ' + (response.data || 'Unknown error')); } }); }; window.testWorkflow = function(workflowId) { var testNumber = prompt('Enter phone number to test (e.g., +1234567890):'); if (testNumber) { $.post(twp_ajax.ajax_url, { action: 'twp_test_call', to_number: testNumber, workflow_id: workflowId, nonce: twp_ajax.nonce }, function(response) { if (response.success && response.data.success) { alert('Test call initiated successfully!'); } else { alert('Error initiating test call: ' + (response.data.error || 'Unknown error')); } }); } }; window.deleteWorkflow = function(workflowId) { if (confirm('Are you sure you want to delete this workflow?')) { $.post(twp_ajax.ajax_url, { action: 'twp_delete_workflow', workflow_id: workflowId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { location.reload(); } }); } }; // Queue Management window.openQueueModal = function() { $('#queue-form')[0].reset(); $('#queue-id').val(''); tb_show('Create New Queue', '#TB_inline?inlineId=queue-modal&width=600&height=550'); }; window.closeQueueModal = function() { tb_remove(); }; window.editQueue = function(queueId) { // Load queue data $.post(twp_ajax.ajax_url, { action: 'twp_get_queue', queue_id: queueId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var queue = response.data; $('#queue-id').val(queue.id); $('[name="queue_name"]').val(queue.queue_name); $('[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); $('[name="wait_music_url"]').val(queue.wait_music_url); $('[name="tts_message"]').val(queue.tts_message); tb_show('Edit Queue: ' + queue.queue_name, '#TB_inline?inlineId=queue-modal&width=600&height=550'); } }); }; window.viewQueueDetails = function(queueId) { // Show queue details in a proper modal $.post(twp_ajax.ajax_url, { action: 'twp_get_queue_details', queue_id: queueId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var details = response.data; var queue = details.queue; var waiting_calls = details.waiting_calls; var avg_wait_time = details.avg_wait_time; var calls = details.calls; var detailsHtml = '
'; detailsHtml += '

' + queue.queue_name + ' Details

'; detailsHtml += '
'; detailsHtml += '
' + waiting_calls + '
'; detailsHtml += '
' + avg_wait_time + '
'; detailsHtml += '
' + queue.max_size + '
'; detailsHtml += '
' + queue.timeout_seconds + ' seconds
'; detailsHtml += '
'; if (calls && calls.length > 0) { detailsHtml += '

Current Calls in Queue

'; detailsHtml += ''; detailsHtml += ''; detailsHtml += ''; calls.forEach(function(call, index) { detailsHtml += ''; detailsHtml += ''; detailsHtml += ''; detailsHtml += ''; detailsHtml += ''; detailsHtml += ''; }); detailsHtml += '
PositionFromWait TimeStatus
' + call.position + '' + call.from_number + '' + call.wait_time + '' + call.status + '
'; } else { detailsHtml += '

No calls currently in queue.

'; } detailsHtml += '
'; // Create and show modal showQueueDetailsModal(detailsHtml); } else { alert('Error loading queue details: ' + (response.data || 'Unknown error')); } }); }; function showQueueDetailsModal(content) { // Remove existing modal if present $('#queue-details-modal').remove(); // Create WordPress-style modal HTML var modalHtml = ` `; // Add modal HTML to body $('body').append(modalHtml); // Use WordPress ThickBox tb_show('Queue Details', '#TB_inline?inlineId=queue-details-modal&width=600&height=400'); } window.closeQueueDetailsModal = function() { tb_remove(); $('#queue-details-modal').remove(); }; window.deleteQueue = function(queueId) { if (confirm('Are you sure you want to delete this queue? All waiting calls will be removed from the queue.')) { $.post(twp_ajax.ajax_url, { action: 'twp_delete_queue', queue_id: queueId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { location.reload(); } else { alert('Error deleting queue: ' + (response.data || 'Unknown error')); } }); } }; $('#queue-form').on('submit', function(e) { e.preventDefault(); var formData = $(this).serialize(); formData += '&action=twp_save_queue&nonce=' + twp_ajax.nonce; $.post(twp_ajax.ajax_url, formData, function(response) { if (response.success) { closeQueueModal(); location.reload(); } else { alert('Error saving queue'); } }); }); // Dashboard Auto-refresh if ($('#active-calls').length) { setInterval(function() { updateDashboardStats(); }, 5000); // Update every 5 seconds } function updateDashboardStats() { $.post(twp_ajax.ajax_url, { action: 'twp_get_dashboard_stats', nonce: twp_ajax.nonce }, function(response) { if (response.success) { $('#active-calls').text(response.data.active_calls); $('#queued-calls').text(response.data.queued_calls); // Update recent calls table if (response.data.recent_calls) { var tableHtml = ''; response.data.recent_calls.forEach(function(call) { tableHtml += ''; tableHtml += '' + call.time + ''; tableHtml += '' + call.from + ''; tableHtml += '' + call.to + ''; tableHtml += '' + call.status + ''; tableHtml += '' + call.duration + ''; tableHtml += ''; }); if (tableHtml === '') { tableHtml = 'No recent calls'; } $('#recent-calls').html(tableHtml); } } }); } // Phone Numbers Management window.refreshNumbers = function() { $('#twp-numbers-list').html('

Loading phone numbers...

'); $.post(twp_ajax.ajax_url, { action: 'twp_get_phone_numbers', nonce: twp_ajax.nonce }, function(response) { if (response.success) { displayPhoneNumbers(response.data); } else { $('#twp-numbers-list').html('

Error loading phone numbers: ' + response.data + '

'); } }); }; window.searchAvailableNumbers = function() { $('#twp-available-numbers').show(); $('#search-results').html(''); }; window.searchNumbers = function() { var countryCode = $('#country-code').val(); var areaCode = $('#area-code').val(); var contains = $('#contains').val(); $('#search-results').html('

Searching available numbers...

'); $.post(twp_ajax.ajax_url, { action: 'twp_search_available_numbers', country_code: countryCode, area_code: areaCode, contains: contains, nonce: twp_ajax.nonce }, function(response) { if (response.success) { displayAvailableNumbers(response.data); } else { $('#search-results').html('

Error searching numbers: ' + response.data + '

'); } }); }; function displayPhoneNumbers(numbers) { if (numbers.length === 0) { $('#twp-numbers-list').html('

No phone numbers found. Buy your first number

'); return; } var html = '
'; numbers.forEach(function(number) { html += '
'; html += '
' + number.phone_number + '
'; html += '
'; html += '
Friendly Name:' + (number.friendly_name || 'N/A') + '
'; html += '
Voice URL:' + (number.voice_url ? 'Configured' : 'Not set') + '
'; html += '
SMS URL:' + (number.sms_url ? 'Configured' : 'Not set') + '
'; html += '
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(); } 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('

' + response.data.transcription + '

'); $('#transcribe-btn').hide(); } else { alert('Error generating transcription'); $('#transcribe-btn').text('Generate Transcription').prop('disabled', false); } }); }; window.filterVoicemails = function() { // TODO: Implement filtering alert('Filtering coming soon'); }; window.exportVoicemails = function() { // TODO: Implement export alert('Export coming soon'); }; // Removed modal click handler - ThickBox handles closing // Agent Group Management Functions window.openGroupModal = function() { $('#group-form')[0].reset(); $('#group-id').val(''); $('#group-modal-title').text('Add New Group'); tb_show('Add New Group', '#TB_inline?inlineId=group-modal&width=600&height=500'); }; window.closeGroupModal = function() { tb_remove(); }; window.saveGroup = function() { var formData = $('#group-form').serialize(); formData += '&action=twp_save_group&nonce=' + twp_ajax.nonce; $.post(twp_ajax.ajax_url, formData, function(response) { if (response.success) { closeGroupModal(); location.reload(); } else { alert('Error saving group: ' + (response.data || 'Unknown error')); } }); }; window.editGroup = function(groupId) { $.post(twp_ajax.ajax_url, { action: 'twp_get_group', group_id: groupId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var group = response.data; $('#group-modal-title').text('Edit Group'); $('#group-id').val(group.id); $('[name="group_name"]').val(group.group_name); $('[name="description"]').val(group.description); $('[name="ring_strategy"]').val(group.ring_strategy); $('[name="timeout_seconds"]').val(group.timeout_seconds); tb_show('Edit Group: ' + group.group_name, '#TB_inline?inlineId=group-modal&width=600&height=500'); } else { alert('Error loading group: ' + (response.data || 'Unknown error')); } }); }; window.deleteGroup = function(groupId) { if (confirm('Are you sure you want to delete this group? All members will be removed.')) { $.post(twp_ajax.ajax_url, { action: 'twp_delete_group', group_id: groupId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { location.reload(); } else { alert('Error deleting group: ' + (response.data || 'Unknown error')); } }); } }; window.manageGroupMembers = function(groupId) { $('#current-group-id').val(groupId); loadGroupMembers(groupId); tb_show('Manage Group Members', '#TB_inline?inlineId=members-modal&width=700&height=600'); }; window.closeMembersModal = function() { tb_remove(); }; function loadGroupMembers(groupId) { $.post(twp_ajax.ajax_url, { action: 'twp_get_group_members', group_id: groupId, nonce: twp_ajax.nonce }, function(response) { if (response.success) { var html = ''; response.data.forEach(function(member) { html += ''; html += '' + member.display_name + ''; html += '' + (member.phone_number || 'No phone set') + ''; html += '' + member.priority + ''; html += '' + (member.is_active ? 'Active' : 'Inactive') + ''; html += ''; html += ''; }); if (html === '') { html = 'No members in this group'; } $('#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 = ` `; // 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 = ` `; // 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 = `

Call Information

Call SID:${call.call_sid || 'N/A'}
From:${call.from_number || 'N/A'}
To:${call.to_number || 'N/A'}
Status:${call.status || 'N/A'}
Duration:${call.duration ? call.duration + ' seconds' : 'N/A'}
Workflow:${call.workflow_name || 'N/A'}
Queue Time:${call.queue_time ? call.queue_time + ' seconds' : 'N/A'}
Created:${call.created_at || 'N/A'}
${call.actions_taken ? `

Actions Taken

${call.actions_taken}
` : ''} ${call.recording_url ? `

Recording

` : ''}
`; // 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 = ` `; // 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')); } }); } }; // 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(); });