push setup
This commit is contained in:
@@ -7,6 +7,7 @@ import camera from './ui/camera.js'; // Default export
|
||||
import audioManager from './ui/audio.js';
|
||||
import * as pushFlic from './services/pushFlicIntegration.js';
|
||||
import { initEnv } from './env-loader.js';
|
||||
import * as pushSettingsUI from './ui/pushSettingsUI.js'; // Import the new push settings UI module
|
||||
|
||||
// Import externalized modules
|
||||
import * as gameActions from './core/gameActions.js';
|
||||
@@ -70,7 +71,10 @@ async function initialize() {
|
||||
ui.elements.resetCancelButton.addEventListener('click', eventHandlers.handleResetCancel);
|
||||
ui.elements.cameraButton.addEventListener('click', eventHandlers.handleCameraButtonClick);
|
||||
|
||||
// 6. Setup Flic action handlers
|
||||
// 6. Initialize Push Notification Settings UI
|
||||
pushSettingsUI.initPushSettingsUI();
|
||||
|
||||
// 7. Setup Flic action handlers
|
||||
const flicActionHandlers = {
|
||||
[config.FLIC_ACTIONS.SINGLE_CLICK]: playerManager.nextPlayer,
|
||||
[config.FLIC_ACTIONS.DOUBLE_CLICK]: playerManager.previousPlayer,
|
||||
@@ -78,14 +82,14 @@ async function initialize() {
|
||||
};
|
||||
serviceWorkerManager.setFlicActionHandlers(flicActionHandlers);
|
||||
|
||||
// 7. Setup Service Worker (which also initializes Flic)
|
||||
// 8. Setup Service Worker (which also initializes Flic)
|
||||
serviceWorkerManager.setupServiceWorker(serviceWorkerManager.handleServiceWorkerMessage);
|
||||
|
||||
// 8. Initial UI Update based on loaded state
|
||||
// 9. Initial UI Update based on loaded state
|
||||
ui.renderPlayers();
|
||||
ui.updateGameButton();
|
||||
|
||||
// 9. Reset running state to paused on load
|
||||
// 10. Reset running state to paused on load
|
||||
if (state.getGameState() === config.GAME_STATES.RUNNING) {
|
||||
console.log("Game was running on load, setting to paused.");
|
||||
state.setGameState(config.GAME_STATES.PAUSED);
|
||||
|
||||
280
src/js/ui/pushSettingsUI.js
Normal file
280
src/js/ui/pushSettingsUI.js
Normal file
@@ -0,0 +1,280 @@
|
||||
// pushSettingsUI.js - UI handling for push notification settings
|
||||
import { setupPushNotifications, forceCredentialsPrompt } 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
|
||||
};
|
||||
|
||||
// --- State ---
|
||||
let currentSubscription = null;
|
||||
|
||||
// --- 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');
|
||||
|
||||
// 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();
|
||||
|
||||
// Show the modal
|
||||
elements.pushSettingsModal.classList.add('active');
|
||||
}
|
||||
|
||||
// Close the push settings modal
|
||||
function closePushSettingsModal() {
|
||||
elements.pushSettingsModal.classList.remove('active');
|
||||
}
|
||||
|
||||
// Update the notification permission status display
|
||||
function updateNotificationStatus() {
|
||||
if (!('Notification' in window)) {
|
||||
elements.notificationPermissionStatus.textContent = 'Not Supported';
|
||||
elements.notificationPermissionStatus.className = 'status-denied';
|
||||
return;
|
||||
}
|
||||
|
||||
const permission = Notification.permission;
|
||||
elements.notificationPermissionStatus.textContent = permission;
|
||||
|
||||
switch (permission) {
|
||||
case 'granted':
|
||||
elements.notificationPermissionStatus.className = 'status-granted';
|
||||
break;
|
||||
case 'denied':
|
||||
elements.notificationPermissionStatus.className = 'status-denied';
|
||||
break;
|
||||
default:
|
||||
elements.notificationPermissionStatus.className = 'status-default';
|
||||
}
|
||||
}
|
||||
|
||||
// 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';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
currentSubscription = await registration.pushManager.getSubscription();
|
||||
|
||||
if (currentSubscription) {
|
||||
elements.subscriptionStatus.textContent = 'Active';
|
||||
elements.subscriptionStatus.className = 'status-active';
|
||||
} else {
|
||||
elements.subscriptionStatus.textContent = 'Not Subscribed';
|
||||
elements.subscriptionStatus.className = 'status-inactive';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking subscription status:', error);
|
||||
elements.subscriptionStatus.textContent = 'Error';
|
||||
elements.subscriptionStatus.className = 'status-denied';
|
||||
}
|
||||
}
|
||||
|
||||
// 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 subscribe to push notifications
|
||||
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));
|
||||
|
||||
// Request notification permission if needed
|
||||
if (Notification.permission !== 'granted') {
|
||||
const permission = await Notification.requestPermission();
|
||||
if (permission !== 'granted') {
|
||||
alert('Notification permission is required for push notifications');
|
||||
updateNotificationStatus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe using the service worker
|
||||
try {
|
||||
await setupPushNotifications();
|
||||
await updateSubscriptionStatus();
|
||||
alert('Subscription successful!');
|
||||
} catch (error) {
|
||||
console.error('Subscription error:', error);
|
||||
alert(`Error subscribing: ${error.message}`);
|
||||
}
|
||||
|
||||
// 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();
|
||||
alert('Successfully unsubscribed from push notifications');
|
||||
} catch (error) {
|
||||
console.error('Error unsubscribing:', error);
|
||||
alert(`Error unsubscribing: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Force resubscription to push notifications
|
||||
async function resubscribeToPush() {
|
||||
try {
|
||||
// Force credential prompt and resubscribe
|
||||
await forceCredentialsPrompt();
|
||||
await updateSubscriptionStatus();
|
||||
} catch (error) {
|
||||
console.error('Error resubscribing:', error);
|
||||
alert(`Error resubscribing: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Manually trigger sendSubscriptionToServer with the current subscription
|
||||
export async function sendSubscriptionToServer() {
|
||||
if (!currentSubscription) {
|
||||
await updateSubscriptionStatus();
|
||||
if (!currentSubscription) {
|
||||
alert('No active subscription available. Please subscribe first.');
|
||||
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) {
|
||||
alert('No valid credentials found. Please set them up first.');
|
||||
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) {
|
||||
alert('Could not get backend URL from config.');
|
||||
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();
|
||||
alert(`Subscription sent successfully: ${result.message || 'OK'}`);
|
||||
} 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 */ }
|
||||
}
|
||||
alert(`Failed to send subscription: ${errorMsg}`);
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`Network error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user