Implement multiple phone numbers per workflow feature

Database Changes:
- Added twp_workflow_phones junction table for many-to-many relationship
- Updated activator to create and manage new table
- Maintained backward compatibility with existing phone_number field

Workflow Management:
- Added set_workflow_phone_numbers() and get_workflow_phone_numbers() methods
- Updated get_workflow_by_phone_number() to check both old and new structures
- Enhanced save/update handlers to support phone_numbers array
- Added AJAX endpoint for retrieving workflow phone numbers

User Interface:
- Replaced single phone number select with dynamic multi-select interface
- Added "Add Number" and "Remove" buttons for managing multiple numbers
- Updated workflow listing to display all assigned phone numbers
- Enhanced JavaScript for phone number management and validation

The webhook routing already supports multiple numbers since get_workflow_by_phone_number()
was updated to check both structures. This feature allows users to assign multiple
Twilio phone numbers to trigger the same workflow.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-13 10:35:21 -07:00
parent 30b0cd355f
commit aa58b45501
5 changed files with 254 additions and 19 deletions

View File

@@ -203,7 +203,9 @@ jQuery(document).ready(function($) {
response.data.forEach(function(number) {
options += '<option value="' + number.phone_number + '">' + number.phone_number + ' (' + number.friendly_name + ')</option>';
});
$('#workflow-phone').html(options);
// Update all workflow phone selects (legacy and new)
$('#workflow-phone, .workflow-phone-select').html(options);
// Call the callback if provided
if (typeof callback === 'function') {
@@ -213,6 +215,20 @@ jQuery(document).ready(function($) {
});
}
function loadWorkflowPhoneNumbers(workflowId, callback) {
$.post(twp_ajax.ajax_url, {
action: 'twp_get_workflow_phone_numbers',
workflow_id: workflowId,
nonce: twp_ajax.nonce
}, function(response) {
if (response.success) {
callback(response.data);
} else {
callback([]);
}
});
}
// Step type button handlers
$(document).on('click', '.step-btn', function() {
var stepType = $(this).data('step-type');
@@ -1088,10 +1104,19 @@ jQuery(document).ready(function($) {
return;
}
// Collect phone numbers from all selects
var phoneNumbers = [];
$('#workflow-phone-numbers select[name="phone_numbers[]"]').each(function() {
var phoneNumber = $(this).val();
if (phoneNumber && phoneNumbers.indexOf(phoneNumber) === -1) {
phoneNumbers.push(phoneNumber);
}
});
var payload = {
action: currentWorkflowId ? 'twp_update_workflow' : 'twp_save_workflow',
workflow_name: workflowData.workflow_name,
phone_number: workflowData.phone_number,
phone_numbers: phoneNumbers,
workflow_data: JSON.stringify({
steps: workflowSteps,
conditions: [],
@@ -1161,11 +1186,46 @@ jQuery(document).ready(function($) {
workflowSteps = [];
}
// Load phone numbers and select the saved one
// Load phone numbers and set up the workflow
loadPhoneNumbers(function() {
$('#workflow-phone').val(phoneNumberToSelect);
// Trigger change event in case there are any listeners
$('#workflow-phone').trigger('change');
// Load assigned phone numbers for this workflow
loadWorkflowPhoneNumbers(workflowId, function(phoneNumbers) {
if (phoneNumbers && phoneNumbers.length > 0) {
// Clear existing phone number inputs
$('#workflow-phone-numbers').empty();
// Add phone number rows
phoneNumbers.forEach(function(phoneNumber, index) {
if (index === 0) {
// First row with Add button
var firstRow = '<div class="phone-number-row">' +
'<select name="phone_numbers[]" class="workflow-phone-select" required></select>' +
'<button type="button" class="button add-phone-number" style="margin-left: 10px;">' +
(phoneNumbers.length === 1 ? 'Add Number' : 'Add Another Number') + '</button>' +
'</div>';
$('#workflow-phone-numbers').append(firstRow);
} else {
// Additional rows with Remove button
var additionalRow = '<div class="phone-number-row" style="margin-top: 10px;">' +
'<select name="phone_numbers[]" class="workflow-phone-select"></select>' +
'<button type="button" class="button remove-phone-number" style="margin-left: 10px; background: #d63638; color: white;">Remove</button>' +
'</div>';
$('#workflow-phone-numbers').append(additionalRow);
}
});
// Repopulate selects and set values
loadPhoneNumbers(function() {
phoneNumbers.forEach(function(phoneNumber, index) {
$('#workflow-phone-numbers .phone-number-row').eq(index).find('select').val(phoneNumber);
});
});
} else {
// Fallback to legacy phone number field
$('#workflow-phone').val(phoneNumberToSelect);
$('#workflow-phone').trigger('change');
}
});
});
updateWorkflowDisplay();
} else {
@@ -2386,6 +2446,36 @@ jQuery(document).ready(function($) {
}
};
// 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 = '<div class="phone-number-row" style="margin-top: 10px;">' +
'<select name="phone_numbers[]" class="workflow-phone-select">' + availableOptions + '</select>' +
'<button type="button" class="button remove-phone-number" style="margin-left: 10px; background: #d63638; color: white;">Remove</button>' +
'</div>';
$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):');