447 lines
17 KiB
JavaScript
447 lines
17 KiB
JavaScript
// pushSettingsUI.js - UI handling for push notification settings
|
|
import { setupPushNotifications } from '../services/serviceWorkerManager.js';
|
|
import { FLIC_BUTTON_ID } from '../config.js';
|
|
|
|
// --- DOM Elements ---
|
|
const elements = {
|
|
pushSettingsButton: null,
|
|
pushSettingsModal: null,
|
|
notificationPermissionStatus: null,
|
|
subscriptionStatus: null,
|
|
pushUsername: null,
|
|
pushPassword: null,
|
|
pushSaveButton: null,
|
|
pushCancelButton: null,
|
|
pushUnsubscribeButton: null,
|
|
pushResubscribeButton: null,
|
|
// Message monitor elements
|
|
swMessagesOutput: null,
|
|
simulateClickButton: null
|
|
};
|
|
|
|
// --- State ---
|
|
let currentSubscription = null;
|
|
let messageListener = null;
|
|
let isMonitoring = false;
|
|
|
|
// --- Initialization ---
|
|
export function initPushSettingsUI() {
|
|
// Cache DOM elements
|
|
elements.pushSettingsButton = document.getElementById('pushSettingsButton');
|
|
elements.pushSettingsModal = document.getElementById('pushSettingsModal');
|
|
elements.notificationPermissionStatus = document.getElementById('notificationPermissionStatus');
|
|
elements.subscriptionStatus = document.getElementById('subscriptionStatus');
|
|
elements.pushUsername = document.getElementById('pushUsername');
|
|
elements.pushPassword = document.getElementById('pushPassword');
|
|
elements.pushSaveButton = document.getElementById('pushSaveButton');
|
|
elements.pushCancelButton = document.getElementById('pushCancelButton');
|
|
elements.pushUnsubscribeButton = document.getElementById('pushUnsubscribeButton');
|
|
elements.pushResubscribeButton = document.getElementById('pushResubscribeButton');
|
|
|
|
// Message Monitor elements
|
|
elements.swMessagesOutput = document.getElementById('swMessagesOutput');
|
|
elements.simulateClickButton = document.getElementById('simulateClickButton');
|
|
|
|
// Set up event listeners
|
|
elements.pushSettingsButton.addEventListener('click', openPushSettingsModal);
|
|
elements.pushCancelButton.addEventListener('click', closePushSettingsModal);
|
|
elements.pushSaveButton.addEventListener('click', saveCredentialsAndSubscribe);
|
|
elements.pushUnsubscribeButton.addEventListener('click', unsubscribeFromPush);
|
|
elements.pushResubscribeButton.addEventListener('click', resubscribeToPush);
|
|
|
|
// Initial status check
|
|
updateNotificationStatus();
|
|
}
|
|
|
|
// --- UI Functions ---
|
|
|
|
// Open the push settings modal and update statuses
|
|
function openPushSettingsModal() {
|
|
// Update status displays
|
|
updateNotificationStatus();
|
|
updateSubscriptionStatus();
|
|
|
|
// Load saved credentials if available
|
|
loadSavedCredentials();
|
|
|
|
// Start monitoring automatically when modal opens
|
|
startMessageMonitoring();
|
|
|
|
// Show the modal
|
|
elements.pushSettingsModal.classList.add('active');
|
|
}
|
|
|
|
// Close the push settings modal
|
|
function closePushSettingsModal() {
|
|
// Stop monitoring when the modal is closed to avoid unnecessary processing
|
|
stopMessageMonitoring();
|
|
elements.pushSettingsModal.classList.remove('active');
|
|
}
|
|
|
|
// --- Message Monitor Functions ---
|
|
|
|
// Start monitoring service worker messages
|
|
function startMessageMonitoring() {
|
|
// If already monitoring, don't set up a new listener
|
|
if (isMonitoring) {
|
|
return;
|
|
}
|
|
|
|
if (!('serviceWorker' in navigator)) {
|
|
elements.swMessagesOutput.textContent = 'Service Worker not supported in this browser.';
|
|
return;
|
|
}
|
|
|
|
// Reset the output area
|
|
elements.swMessagesOutput.textContent = 'Monitoring for service worker messages...';
|
|
|
|
// Create and register the message listener
|
|
messageListener = function(event) {
|
|
const now = new Date().toISOString();
|
|
const formattedMessage = `[${now}] Message received: \n${JSON.stringify(event.data, null, 2)}\n\n`;
|
|
elements.swMessagesOutput.textContent += formattedMessage;
|
|
|
|
// Auto-scroll to the bottom
|
|
elements.swMessagesOutput.scrollTop = elements.swMessagesOutput.scrollHeight;
|
|
};
|
|
|
|
// Add the listener
|
|
navigator.serviceWorker.addEventListener('message', messageListener);
|
|
isMonitoring = true;
|
|
}
|
|
|
|
// Stop monitoring service worker messages
|
|
function stopMessageMonitoring() {
|
|
if (messageListener) {
|
|
navigator.serviceWorker.removeEventListener('message', messageListener);
|
|
messageListener = null;
|
|
isMonitoring = false;
|
|
}
|
|
}
|
|
|
|
// Update the notification permission status display
|
|
function updateNotificationStatus() {
|
|
if (!('Notification' in window)) {
|
|
elements.notificationPermissionStatus.textContent = 'Not Supported';
|
|
elements.notificationPermissionStatus.className = 'status-denied';
|
|
// Disable subscribe button when notifications are not supported
|
|
elements.pushResubscribeButton.disabled = true;
|
|
elements.pushResubscribeButton.classList.add('disabled');
|
|
return;
|
|
}
|
|
|
|
const permission = Notification.permission;
|
|
elements.notificationPermissionStatus.textContent = permission;
|
|
|
|
switch (permission) {
|
|
case 'granted':
|
|
elements.notificationPermissionStatus.className = 'status-granted';
|
|
// Enable subscribe button when permission is granted
|
|
elements.pushResubscribeButton.disabled = false;
|
|
elements.pushResubscribeButton.classList.remove('disabled');
|
|
break;
|
|
case 'denied':
|
|
elements.notificationPermissionStatus.className = 'status-denied';
|
|
// Disable subscribe button when permission is denied
|
|
elements.pushResubscribeButton.disabled = true;
|
|
elements.pushResubscribeButton.classList.add('disabled');
|
|
break;
|
|
default:
|
|
elements.notificationPermissionStatus.className = 'status-default';
|
|
// Enable subscribe button for default state (prompt)
|
|
elements.pushResubscribeButton.disabled = false;
|
|
elements.pushResubscribeButton.classList.remove('disabled');
|
|
}
|
|
}
|
|
|
|
// Update the subscription status display
|
|
async function updateSubscriptionStatus() {
|
|
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
|
elements.subscriptionStatus.textContent = 'Not Supported';
|
|
elements.subscriptionStatus.className = 'status-denied';
|
|
// Disable unsubscribe button when not supported
|
|
elements.pushUnsubscribeButton.disabled = true;
|
|
// Set subscribe button text
|
|
elements.pushResubscribeButton.textContent = 'Subscribe';
|
|
// Disable simulate button when not supported
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
currentSubscription = await registration.pushManager.getSubscription();
|
|
|
|
if (currentSubscription) {
|
|
elements.subscriptionStatus.textContent = 'active';
|
|
elements.subscriptionStatus.className = 'status-active';
|
|
// Enable unsubscribe button when subscription is active
|
|
elements.pushUnsubscribeButton.disabled = false;
|
|
// Change subscribe button text to "Re-subscribe"
|
|
elements.pushResubscribeButton.textContent = 'Re-subscribe';
|
|
// Enable simulate button when subscription is active
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = false;
|
|
}
|
|
} else {
|
|
elements.subscriptionStatus.textContent = 'Not Subscribed';
|
|
elements.subscriptionStatus.className = 'status-inactive';
|
|
// Disable unsubscribe button when not subscribed
|
|
elements.pushUnsubscribeButton.disabled = true;
|
|
// Set subscribe button text
|
|
elements.pushResubscribeButton.textContent = 'Subscribe';
|
|
// Disable simulate button when not subscribed
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = true;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking subscription status:', error);
|
|
elements.subscriptionStatus.textContent = 'Error';
|
|
elements.subscriptionStatus.className = 'status-denied';
|
|
// Disable unsubscribe button on error
|
|
elements.pushUnsubscribeButton.disabled = true;
|
|
// Set subscribe button text
|
|
elements.pushResubscribeButton.textContent = 'Subscribe';
|
|
// Disable simulate button on error
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load saved credentials from localStorage
|
|
function loadSavedCredentials() {
|
|
try {
|
|
const storedAuth = localStorage.getItem('basicAuthCredentials');
|
|
if (storedAuth) {
|
|
const credentials = JSON.parse(storedAuth);
|
|
if (credentials.username && credentials.password) {
|
|
elements.pushUsername.value = credentials.username;
|
|
elements.pushPassword.value = credentials.password;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading saved credentials:', error);
|
|
}
|
|
}
|
|
|
|
// --- Action Functions ---
|
|
|
|
// Save credentials and close the modal
|
|
async function saveCredentialsAndSubscribe() {
|
|
const username = elements.pushUsername.value.trim();
|
|
const password = elements.pushPassword.value.trim();
|
|
|
|
if (!username || !password) {
|
|
alert('Please enter both username and password');
|
|
return;
|
|
}
|
|
|
|
// Save credentials to localStorage
|
|
const credentials = { username, password };
|
|
localStorage.setItem('basicAuthCredentials', JSON.stringify(credentials));
|
|
|
|
// Close the modal
|
|
closePushSettingsModal();
|
|
}
|
|
|
|
// Unsubscribe from push notifications
|
|
async function unsubscribeFromPush() {
|
|
if (!currentSubscription) {
|
|
alert('No active subscription to unsubscribe from');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await currentSubscription.unsubscribe();
|
|
await updateSubscriptionStatus();
|
|
// No success alert
|
|
} catch (error) {
|
|
console.error('Error unsubscribing:', error);
|
|
alert(`Error unsubscribing: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Subscribe to push notifications
|
|
async function resubscribeToPush() {
|
|
try {
|
|
let username = elements.pushUsername.value.trim();
|
|
let password = elements.pushPassword.value.trim();
|
|
|
|
// If fields are empty, try to use stored credentials
|
|
if (!username || !password) {
|
|
try {
|
|
const storedAuth = localStorage.getItem('basicAuthCredentials');
|
|
if (storedAuth) {
|
|
const credentials = JSON.parse(storedAuth);
|
|
if (credentials.username && credentials.password) {
|
|
username = credentials.username;
|
|
password = credentials.password;
|
|
|
|
// Update the form fields with stored values
|
|
elements.pushUsername.value = username;
|
|
elements.pushPassword.value = password;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading stored credentials:', error);
|
|
}
|
|
}
|
|
|
|
// Check if we have credentials, show alert if missing
|
|
if (!username || !password) {
|
|
console.log('No credentials available. Showing alert.');
|
|
alert('Please enter your username and password to subscribe.');
|
|
return;
|
|
}
|
|
|
|
// Save the credentials to localStorage
|
|
const credentials = { username, password };
|
|
localStorage.setItem('basicAuthCredentials', JSON.stringify(credentials));
|
|
console.log('Saved credentials to localStorage');
|
|
|
|
// Use the credentials to subscribe
|
|
await setupPushNotifications();
|
|
|
|
// Wait a moment for the subscription to complete
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// Get the updated subscription
|
|
const registration = await navigator.serviceWorker.ready;
|
|
currentSubscription = await registration.pushManager.getSubscription();
|
|
|
|
// Update the UI directly
|
|
if (currentSubscription && elements.subscriptionStatus) {
|
|
elements.subscriptionStatus.textContent = 'active';
|
|
elements.subscriptionStatus.className = 'status-active';
|
|
// Enable unsubscribe button when subscription is active
|
|
elements.pushUnsubscribeButton.disabled = false;
|
|
// Change subscribe button text to "Re-subscribe"
|
|
elements.pushResubscribeButton.textContent = 'Re-subscribe';
|
|
// Enable simulate button when subscription is active
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = false;
|
|
}
|
|
} else {
|
|
// Disable unsubscribe button when not subscribed
|
|
elements.pushUnsubscribeButton.disabled = true;
|
|
// Set subscribe button text
|
|
elements.pushResubscribeButton.textContent = 'Subscribe';
|
|
// Disable simulate button when not subscribed
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = true;
|
|
}
|
|
// Fall back to the standard update function
|
|
await updateSubscriptionStatus();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error subscribing:', error);
|
|
alert(`Error subscribing: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
// Manually trigger sendSubscriptionToServer with the current subscription
|
|
export async function sendSubscriptionToServer() {
|
|
if (!currentSubscription) {
|
|
await updateSubscriptionStatus();
|
|
if (!currentSubscription) {
|
|
// No alert, just return silently
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Get stored credentials
|
|
let credentials;
|
|
try {
|
|
const storedAuth = localStorage.getItem('basicAuthCredentials');
|
|
if (storedAuth) {
|
|
credentials = JSON.parse(storedAuth);
|
|
if (!credentials.username || !credentials.password) {
|
|
throw new Error('Invalid credentials');
|
|
}
|
|
} else {
|
|
throw new Error('No stored credentials');
|
|
}
|
|
} catch (error) {
|
|
// No alert, just open the modal to let the user set credentials
|
|
openPushSettingsModal();
|
|
return;
|
|
}
|
|
|
|
// Create Basic Auth header
|
|
const createBasicAuthHeader = (creds) => {
|
|
return 'Basic ' + btoa(`${creds.username}:${creds.password}`);
|
|
};
|
|
|
|
const headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': createBasicAuthHeader(credentials)
|
|
};
|
|
|
|
// Import the backend URL from config
|
|
let backendUrl;
|
|
try {
|
|
const configModule = await import('../config.js');
|
|
backendUrl = configModule.BACKEND_URL;
|
|
} catch (error) {
|
|
// No alert, just log the error and return
|
|
console.error('Could not get backend URL from config:', error);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Make the request to the server
|
|
const response = await fetch(`${backendUrl}/subscribe`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
button_id: FLIC_BUTTON_ID,
|
|
subscription: currentSubscription
|
|
}),
|
|
headers: headers,
|
|
credentials: 'include'
|
|
});
|
|
|
|
if (response.ok) {
|
|
const result = await response.json();
|
|
// No success alert
|
|
|
|
// Update the currentSubscription variable
|
|
const registration = await navigator.serviceWorker.ready;
|
|
currentSubscription = await registration.pushManager.getSubscription();
|
|
|
|
// Directly update the subscription status element in the DOM
|
|
if (currentSubscription && elements.subscriptionStatus) {
|
|
elements.subscriptionStatus.textContent = 'active';
|
|
elements.subscriptionStatus.className = 'status-active';
|
|
// Enable unsubscribe button when subscription is active
|
|
elements.pushUnsubscribeButton.disabled = false;
|
|
// Change subscribe button text to "Re-subscribe"
|
|
elements.pushResubscribeButton.textContent = 'Re-subscribe';
|
|
// Enable simulate button when subscription is active
|
|
if (elements.simulateClickButton) {
|
|
elements.simulateClickButton.disabled = false;
|
|
}
|
|
}
|
|
} else {
|
|
let errorMsg = `Server error: ${response.status}`;
|
|
if (response.status === 401 || response.status === 403) {
|
|
localStorage.removeItem('basicAuthCredentials');
|
|
errorMsg = 'Authentication failed. Credentials cleared.';
|
|
} else {
|
|
try {
|
|
const errorData = await response.json();
|
|
errorMsg = errorData.message || errorMsg;
|
|
} catch (e) { /* use default */ }
|
|
}
|
|
// No error alert, just log the error
|
|
console.error(`Failed to send subscription: ${errorMsg}`);
|
|
}
|
|
} catch (error) {
|
|
// No error alert, just log the error
|
|
console.error(`Network error: ${error.message}`);
|
|
}
|
|
}
|