Add background notifications and fix Discord/Slack notification bugs
Background Notification Features: - Implement Web Push Notifications for alerts when browser is minimized - Add Service Worker for persistent background notification support - Integrate Page Visibility API to detect when page is in background - Add browser notification permission request with user consent flow - Create more aggressive background polling (10 seconds) when page hidden - Add vibration patterns for mobile device alerts Bug Fixes: - Fix Discord/Slack notification parameter order bug preventing delivery - Add comprehensive logging for notification debugging - Correct webhook function signatures for proper data passing Mobile Enhancements: - Support system notifications on Android browsers - Add click-to-focus functionality for notifications - Implement background alert system for multitasking - Add notification button with visual feedback 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,9 @@
|
||||
let alertSound = null;
|
||||
let alertInterval = null;
|
||||
let alertEnabled = false;
|
||||
let notificationPermission = 'default';
|
||||
let backgroundAlertInterval = null;
|
||||
let isPageVisible = true;
|
||||
|
||||
// Initialize when document is ready
|
||||
$(document).ready(function() {
|
||||
@@ -33,6 +36,8 @@
|
||||
loadPhoneNumbers();
|
||||
loadUserQueues();
|
||||
initVoicemailSection();
|
||||
initializeNotifications();
|
||||
initializePageVisibility();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -525,6 +530,20 @@
|
||||
if (currentWaiting > previousWaiting) {
|
||||
console.log('New call detected in queue:', queue.queue_name);
|
||||
newCallDetected = true;
|
||||
|
||||
// Show browser notification for new call
|
||||
if (notificationPermission === 'granted') {
|
||||
showBrowserNotification('📞 New Call in Queue!', {
|
||||
body: `${queue.queue_name}: ${currentWaiting} call${currentWaiting > 1 ? 's' : ''} waiting`,
|
||||
icon: '📞',
|
||||
vibrate: [300, 200, 300],
|
||||
requireInteraction: true,
|
||||
tag: `queue-${queue.id}`,
|
||||
data: {
|
||||
queueId: queue.id
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
lastQueueUpdate[queueId] = currentWaiting;
|
||||
@@ -980,6 +999,9 @@
|
||||
if (alertInterval) {
|
||||
clearInterval(alertInterval);
|
||||
}
|
||||
if (backgroundAlertInterval) {
|
||||
clearInterval(backgroundAlertInterval);
|
||||
}
|
||||
if (twilioDevice) {
|
||||
twilioDevice.destroy();
|
||||
}
|
||||
@@ -1140,6 +1162,217 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize browser notifications
|
||||
*/
|
||||
function initializeNotifications() {
|
||||
// Register service worker for background notifications
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/wp-content/plugins/twilio-wp-plugin/assets/js/twp-service-worker.js')
|
||||
.then(function(registration) {
|
||||
console.log('Service Worker registered:', registration);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log('Service Worker registration failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Check if browser supports notifications
|
||||
if (!('Notification' in window)) {
|
||||
console.log('This browser does not support notifications');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check current permission status
|
||||
notificationPermission = Notification.permission;
|
||||
|
||||
// Request permission if not already granted or denied
|
||||
if (notificationPermission === 'default') {
|
||||
// Add a button to request permission
|
||||
if ($('#twp-queue-global-actions').length > 0) {
|
||||
const $notificationBtn = $('<button>')
|
||||
.attr('id', 'twp-enable-notifications')
|
||||
.addClass('twp-btn twp-btn-info')
|
||||
.html('🔔 Enable Notifications')
|
||||
.on('click', requestNotificationPermission);
|
||||
|
||||
$('#twp-queue-global-actions .global-queue-actions').append($notificationBtn);
|
||||
}
|
||||
} else if (notificationPermission === 'granted') {
|
||||
console.log('Notifications are enabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request notification permission from user
|
||||
*/
|
||||
function requestNotificationPermission() {
|
||||
Notification.requestPermission().then(function(permission) {
|
||||
notificationPermission = permission;
|
||||
|
||||
if (permission === 'granted') {
|
||||
showMessage('Notifications enabled! You will be alerted even when the browser is in the background.', 'success');
|
||||
$('#twp-enable-notifications').hide();
|
||||
|
||||
// Show test notification
|
||||
showBrowserNotification('Notifications Enabled', {
|
||||
body: 'You will now receive alerts for incoming calls',
|
||||
icon: '📞',
|
||||
tag: 'test-notification'
|
||||
});
|
||||
} else if (permission === 'denied') {
|
||||
showMessage('Notifications blocked. Please enable them in your browser settings.', 'error');
|
||||
$('#twp-enable-notifications').text('❌ Notifications Blocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show browser notification
|
||||
*/
|
||||
function showBrowserNotification(title, options = {}) {
|
||||
if (notificationPermission !== 'granted') {
|
||||
return;
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
body: '',
|
||||
icon: '/wp-content/plugins/twilio-wp-plugin/assets/images/phone-icon.png',
|
||||
badge: '/wp-content/plugins/twilio-wp-plugin/assets/images/phone-badge.png',
|
||||
vibrate: [200, 100, 200],
|
||||
requireInteraction: true, // Keep notification visible until clicked
|
||||
tag: 'twp-call-notification',
|
||||
data: options.data || {}
|
||||
};
|
||||
|
||||
const notificationOptions = Object.assign(defaultOptions, options);
|
||||
|
||||
try {
|
||||
const notification = new Notification(title, notificationOptions);
|
||||
|
||||
// Handle notification click
|
||||
notification.onclick = function(event) {
|
||||
event.preventDefault();
|
||||
window.focus();
|
||||
notification.close();
|
||||
|
||||
// If there's queue data, select that queue
|
||||
if (event.target.data && event.target.data.queueId) {
|
||||
selectQueue(event.target.data.queueId);
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-close after 30 seconds if not required interaction
|
||||
if (!notificationOptions.requireInteraction) {
|
||||
setTimeout(function() {
|
||||
notification.close();
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
return notification;
|
||||
} catch (error) {
|
||||
console.error('Failed to show notification:', error);
|
||||
// Fallback to service worker notification if available
|
||||
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
||||
navigator.serviceWorker.ready.then(function(registration) {
|
||||
registration.showNotification(title, notificationOptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize page visibility handling
|
||||
*/
|
||||
function initializePageVisibility() {
|
||||
// Set up visibility change detection
|
||||
let hidden, visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') {
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.msHidden !== 'undefined') {
|
||||
hidden = 'msHidden';
|
||||
visibilityChange = 'msvisibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
// Handle visibility change
|
||||
document.addEventListener(visibilityChange, function() {
|
||||
isPageVisible = !document[hidden];
|
||||
|
||||
if (isPageVisible) {
|
||||
console.log('Page is now visible');
|
||||
// Resume normal operations
|
||||
if (backgroundAlertInterval) {
|
||||
clearInterval(backgroundAlertInterval);
|
||||
backgroundAlertInterval = null;
|
||||
}
|
||||
} else {
|
||||
console.log('Page is now hidden/background');
|
||||
// Start more aggressive notifications for background
|
||||
if (alertEnabled && userQueues.some(q => parseInt(q.current_waiting) > 0)) {
|
||||
startBackgroundAlerts();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Also handle window focus/blur for better mobile support
|
||||
$(window).on('focus', function() {
|
||||
isPageVisible = true;
|
||||
if (backgroundAlertInterval) {
|
||||
clearInterval(backgroundAlertInterval);
|
||||
backgroundAlertInterval = null;
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on('blur', function() {
|
||||
isPageVisible = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start background alerts with notifications
|
||||
*/
|
||||
function startBackgroundAlerts() {
|
||||
if (backgroundAlertInterval) return;
|
||||
|
||||
// Check and notify every 10 seconds when in background
|
||||
backgroundAlertInterval = setInterval(function() {
|
||||
const waitingQueues = userQueues.filter(q => parseInt(q.current_waiting) > 0);
|
||||
|
||||
if (waitingQueues.length > 0 && !currentCall) {
|
||||
// Count total waiting calls
|
||||
const totalWaiting = waitingQueues.reduce((sum, q) => sum + parseInt(q.current_waiting), 0);
|
||||
|
||||
// Show browser notification
|
||||
showBrowserNotification(`${totalWaiting} Call${totalWaiting > 1 ? 's' : ''} Waiting!`, {
|
||||
body: waitingQueues.map(q => `${q.queue_name}: ${q.current_waiting} waiting`).join('\n'),
|
||||
icon: '📞',
|
||||
vibrate: [300, 200, 300, 200, 300],
|
||||
requireInteraction: true,
|
||||
tag: 'queue-alert',
|
||||
data: {
|
||||
queueId: waitingQueues[0].id
|
||||
}
|
||||
});
|
||||
|
||||
// Also try to play sound if possible
|
||||
try {
|
||||
playAlertSound();
|
||||
} catch (e) {
|
||||
// Sound might be blocked in background
|
||||
}
|
||||
} else if (waitingQueues.length === 0) {
|
||||
// No more calls, stop background alerts
|
||||
clearInterval(backgroundAlertInterval);
|
||||
backgroundAlertInterval = null;
|
||||
}
|
||||
}, 10000); // Every 10 seconds in background
|
||||
}
|
||||
|
||||
// Load alert preference on init
|
||||
loadAlertPreference();
|
||||
|
||||
|
Reference in New Issue
Block a user