Diverse änderungen am Push system

This commit is contained in:
2025-09-16 21:00:12 +02:00
parent 69e3985af3
commit b2fc63e2d0
7 changed files with 992 additions and 164 deletions

View File

@@ -29,42 +29,259 @@
});
}
// Request notification permission on page load
if ('Notification' in window) {
if (Notification.permission === 'default') {
Notification.requestPermission().then(function(permission) {
if (permission === 'granted') {
console.log('✅ Notification permission granted');
// Subscribe to push notifications
subscribeToPush();
} else {
console.log('❌ Notification permission denied');
}
});
}
}
// Don't automatically request notification permission
// User must click the button to enable push notifications
// Convert VAPID key from base64url to Uint8Array
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
// Convert ArrayBuffer to Base64 string
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
// Push notification state
let pushSubscription = null;
let pushEnabled = false;
// Subscribe to push notifications
async function subscribeToPush() {
try {
console.log('🔔 Starting push subscription...');
const registration = await navigator.serviceWorker.ready;
const vapidPublicKey = 'BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds';
const applicationServerKey = urlBase64ToUint8Array(vapidPublicKey);
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: 'BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds'
applicationServerKey: applicationServerKey
});
// Send subscription to server
await fetch('/api/v1/public/subscribe', {
pushSubscription = subscription;
// Generate or get player ID
let playerId = window.currentPlayerId;
if (!playerId) {
// Generate a UUID for the player
playerId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
console.log(`📱 Generated player ID: ${playerId}`);
} else {
console.log(`📱 Using existing player ID: ${playerId}`);
}
// Convert ArrayBuffer keys to Base64 strings
const p256dhKey = subscription.getKey('p256dh');
const authKey = subscription.getKey('auth');
// Convert ArrayBuffer to Base64 URL-safe string
const p256dhString = arrayBufferToBase64(p256dhKey);
const authString = arrayBufferToBase64(authKey);
console.log('📱 Converted keys to Base64 strings');
console.log('📱 p256dh length:', p256dhString.length);
console.log('📱 auth length:', authString.length);
// Send subscription to server with player ID
const response = await fetch('/api/v1/public/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(subscription)
body: JSON.stringify({
endpoint: subscription.endpoint,
keys: {
p256dh: p256dhString,
auth: authString
},
playerId: playerId
})
});
console.log('✅ Push subscription successful');
const result = await response.json();
if (result.success) {
pushEnabled = true;
updatePushButton();
console.log('✅ Push subscription successful');
// Store player ID for notifications
if (result.playerId) {
localStorage.setItem('pushPlayerId', result.playerId);
}
} else {
throw new Error(result.message);
}
} catch (error) {
console.error('❌ Push subscription failed:', error);
pushEnabled = false;
updatePushButton();
}
}
// Unsubscribe from push notifications
async function unsubscribeFromPush() {
try {
console.log('🔕 Unsubscribing from push notifications...');
// Get player ID from localStorage
const playerId = localStorage.getItem('pushPlayerId');
if (pushSubscription) {
await pushSubscription.unsubscribe();
pushSubscription = null;
console.log('✅ Local push subscription removed');
}
// Notify server to remove from database
if (playerId) {
try {
const response = await fetch('/api/v1/public/unsubscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ playerId: playerId })
});
const result = await response.json();
if (result.success) {
console.log('✅ Server notified - subscription removed from database');
} else {
console.warn('⚠️ Server notification failed:', result.message);
}
} catch (error) {
console.warn('⚠️ Failed to notify server:', error);
}
}
// Clear stored player ID
localStorage.removeItem('pushPlayerId');
pushEnabled = false;
updatePushButton();
console.log('🔕 Push notifications disabled');
} catch (error) {
console.error('❌ Push unsubscribe failed:', error);
pushEnabled = false;
updatePushButton();
}
}
// Toggle push notifications
async function togglePushNotifications() {
if (pushEnabled) {
await unsubscribeFromPush();
} else {
// Check notification permission first
if (Notification.permission === 'denied') {
alert('Push-Benachrichtigungen sind blockiert. Bitte erlaube sie in den Browser-Einstellungen.');
return;
}
if (Notification.permission === 'default') {
const permission = await Notification.requestPermission();
if (permission !== 'granted') {
alert('Push-Benachrichtigungen wurden nicht erlaubt.');
return;
}
}
await subscribeToPush();
}
}
// Update push button appearance
function updatePushButton() {
const button = document.getElementById('pushButton');
if (!button) {
console.log('❌ Push button not found in DOM');
return;
}
console.log(`🔔 Updating push button - Status: ${pushEnabled ? 'ENABLED' : 'DISABLED'}`);
if (pushEnabled) {
button.classList.add('active');
button.setAttribute('data-de', '🔕 Push deaktivieren');
button.setAttribute('data-en', '🔕 Disable Push');
button.textContent = '🔕 Push deaktivieren';
console.log('✅ Button updated to: Push deaktivieren (RED)');
} else {
button.classList.remove('active');
button.setAttribute('data-de', '🔔 Push aktivieren');
button.setAttribute('data-en', '🔔 Enable Push');
button.textContent = '🔔 Push aktivieren';
console.log('✅ Button updated to: Push aktivieren (GREEN)');
}
}
// Check existing push subscription on page load
async function checkPushStatus() {
try {
console.log('🔍 Checking push status...');
if (!('serviceWorker' in navigator)) {
console.log('❌ Service Worker not supported');
pushEnabled = false;
updatePushButton();
return;
}
if (!('PushManager' in window)) {
console.log('❌ Push Manager not supported');
pushEnabled = false;
updatePushButton();
return;
}
const registration = await navigator.serviceWorker.ready;
console.log('✅ Service Worker ready');
const subscription = await registration.pushManager.getSubscription();
console.log('📱 Current subscription:', subscription ? 'EXISTS' : 'NONE');
if (subscription) {
pushSubscription = subscription;
pushEnabled = true;
updatePushButton();
console.log('✅ Existing push subscription found and activated');
// Also check if we have a stored player ID
const storedPlayerId = localStorage.getItem('pushPlayerId');
if (storedPlayerId) {
console.log(`📱 Push subscription linked to player: ${storedPlayerId}`);
}
} else {
pushEnabled = false;
updatePushButton();
console.log(' No existing push subscription found');
}
} catch (error) {
console.error('❌ Error checking push status:', error);
pushEnabled = false;
updatePushButton();
}
}
</script>
@@ -84,6 +301,7 @@
<div class="user-avatar" id="userAvatar">U</div>
<span id="userEmail">user@example.com</span>
</div>
<button class="btn btn-push" id="pushButton" onclick="togglePushNotifications()" data-de="🔔 Push aktivieren" data-en="🔔 Enable Push">🔔 Push aktivieren</button>
<a href="/" class="btn btn-primary" data-de="Zurück zu Zeiten" data-en="Back to Times">Back to Times</a>
<button class="btn btn-logout" onclick="logout()" data-de="Logout" data-en="Logout">Logout</button>
</div>