diff --git a/assets/css/browser-phone-frontend.css b/assets/css/browser-phone-frontend.css index 78fe1ca..76c6f6d 100644 --- a/assets/css/browser-phone-frontend.css +++ b/assets/css/browser-phone-frontend.css @@ -56,8 +56,8 @@ } .status-text { - font-weight: 500; - color: #495057; + font-weight: 600; + color: #212529; } @keyframes pulse { @@ -74,8 +74,8 @@ .twp-phone-selection label { display: block; margin-bottom: 8px; - font-weight: 500; - color: #495057; + font-weight: 600; + color: #212529; } .twp-select { @@ -85,7 +85,7 @@ border-radius: 8px; font-size: 16px; background: #fff; - color: #495057; + color: #212529; appearance: none; background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); background-position: right 12px center; @@ -289,8 +289,8 @@ padding: 8px; background: #f8f9fa; border-radius: 4px; - color: #495057; - font-weight: 500; + color: #212529; + font-weight: 600; } /* Queue Management Section */ @@ -317,9 +317,10 @@ .queue-loading, .no-queues { text-align: center; - color: #6c757d; + color: #495057; font-style: italic; padding: 20px; + font-weight: 500; } .no-queues { @@ -377,7 +378,7 @@ justify-content: space-between; align-items: center; font-size: 0.9rem; - color: #6c757d; + color: #495057; } .queue-waiting { @@ -418,7 +419,7 @@ justify-content: center; gap: 20px; font-size: 0.9rem; - color: #6c757d; + color: #495057; } .queue-stats span { @@ -552,27 +553,59 @@ /* Dark mode support */ @media (prefers-color-scheme: dark) { .twp-browser-phone-container { - background: #2d3748; - color: #e2e8f0; + background: #1a202c; + color: #f7fafc; } .twp-connection-status, .twp-call-info, - .twp-queue-controls { - background: #4a5568; - border-color: #718096; + .twp-queue-controls, + .twp-queue-section { + background: #2d3748; + border-color: #4a5568; } .twp-select, #twp-dial-number, .twp-dial-btn { - background: #4a5568; - border-color: #718096; - color: #e2e8f0; + background: #2d3748; + border-color: #4a5568; + color: #f7fafc; } .call-status { + background: #1a202c; + color: #f7fafc; + } + + .queue-item { background: #2d3748; + border-color: #4a5568; + color: #f7fafc; + } + + .queue-item:hover, + .queue-item.selected { + background: #4a5568; + border-color: #63b3ed; + } + + .queue-name, + .status-text, + .twp-phone-selection label { + color: #f7fafc; + } + + .queue-info, + .queue-stats, + .queue-loading, + .no-queues { + color: #cbd5e0; + } + + .no-queues { + background: #2d3748; + border-color: #4a5568; } } diff --git a/assets/js/browser-phone-frontend.js b/assets/js/browser-phone-frontend.js index 025319e..1c845eb 100644 --- a/assets/js/browser-phone-frontend.js +++ b/assets/js/browser-phone-frontend.js @@ -27,32 +27,61 @@ loadUserQueues(); }); + /** + * Wait for Twilio SDK to load + */ + function waitForTwilioSDK(callback) { + let attempts = 0; + const maxAttempts = 50; // 5 seconds max + + function checkTwilio() { + if (typeof Twilio !== 'undefined' && Twilio.Device) { + callback(); + return; + } + + attempts++; + if (attempts >= maxAttempts) { + updateStatus('offline', 'SDK load timeout'); + showMessage('Twilio SDK failed to load within 5 seconds. Please check your internet connection and refresh the page.', 'error'); + return; + } + + setTimeout(checkTwilio, 100); + } + + checkTwilio(); + } + /** * Initialize the browser phone */ function initializeBrowserPhone() { updateStatus('connecting', 'Initializing...'); - // Generate capability token - $.ajax({ - url: twp_frontend_ajax.ajax_url, - method: 'POST', - data: { - action: 'twp_generate_capability_token', - nonce: twp_frontend_ajax.nonce - }, - success: function(response) { - if (response.success) { - setupTwilioDevice(response.data.token); - } else { - updateStatus('offline', 'Failed to initialize'); - showMessage('Failed to initialize browser phone: ' + (response.data || 'Unknown error'), 'error'); + // Wait for Twilio SDK to load, then initialize + waitForTwilioSDK(function() { + // Generate capability token + $.ajax({ + url: twp_frontend_ajax.ajax_url, + method: 'POST', + data: { + action: 'twp_generate_capability_token', + nonce: twp_frontend_ajax.nonce + }, + success: function(response) { + if (response.success) { + setupTwilioDevice(response.data.token); + } else { + updateStatus('offline', 'Failed to initialize'); + showMessage('Failed to initialize browser phone: ' + (response.data || 'Unknown error'), 'error'); + } + }, + error: function() { + updateStatus('offline', 'Connection failed'); + showMessage('Failed to connect to server', 'error'); } - }, - error: function() { - updateStatus('offline', 'Connection failed'); - showMessage('Failed to connect to server', 'error'); - } + }); }); } @@ -60,6 +89,14 @@ * Setup Twilio Device */ function setupTwilioDevice(token) { + // Check if Twilio SDK is loaded + if (typeof Twilio === 'undefined' || !Twilio.Device) { + updateStatus('offline', 'Twilio SDK not loaded'); + showMessage('Twilio SDK failed to load. Please refresh the page.', 'error'); + console.error('Twilio SDK is not available'); + return; + } + try { twilioDevice = new Twilio.Device(token, { logLevel: 1, diff --git a/includes/class-twp-shortcodes.php b/includes/class-twp-shortcodes.php index 2b577fb..a6d9794 100644 --- a/includes/class-twp-shortcodes.php +++ b/includes/class-twp-shortcodes.php @@ -32,7 +32,7 @@ class TWP_Shortcodes { 'https://sdk.twilio.com/js/voice/2.11.1/twilio.min.js', array(), '2.11.1', - true + false // Load in head to ensure it's available ); // Enqueue our browser phone script @@ -180,10 +180,8 @@ class TWP_Shortcodes { - - + +