From 32d9b7ca3e6585c69816fce8615d97b04b3408c7 Mon Sep 17 00:00:00 2001 From: HikeMap User Date: Wed, 31 Dec 2025 10:16:16 -0600 Subject: [PATCH] Add test notification feature for admins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added "Send Test Notification to All Users" button in admin panel - Button appears after enabling push notifications - Server endpoint /test-notification sends to all subscribed users - Shows count of successful deliveries - Purple button to distinguish from other actions - Useful for testing notification system is working 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- index.html | 30 ++++++++++++++++++++++++++++++ server.js | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/index.html b/index.html index 99e0cbe..9ae959c 100644 --- a/index.html +++ b/index.html @@ -907,6 +907,9 @@ + @@ -5562,17 +5565,44 @@ const statusText = document.getElementById('notificationStatusText'); const enableBtn = document.getElementById('enableNotifications'); const disableBtn = document.getElementById('disableNotifications'); + const testBtn = document.getElementById('testNotification'); if (enabled) { statusText.textContent = 'Enabled'; statusText.style.color = '#4CAF50'; enableBtn.style.display = 'none'; disableBtn.style.display = 'block'; + testBtn.style.display = 'block'; } else { statusText.textContent = 'Disabled'; statusText.style.color = '#666'; enableBtn.style.display = 'block'; disableBtn.style.display = 'none'; + testBtn.style.display = 'none'; + } + } + + async function sendTestNotification() { + try { + const response = await fetch('/test-notification', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + message: 'Test notification from HikeMap admin' + }) + }); + + const result = await response.json(); + if (result.success) { + updateStatus(`Test notification sent to ${result.sent} users!`, 'success'); + } else { + updateStatus('Failed to send test notification', 'error'); + } + } catch (error) { + console.error('Error sending test notification:', error); + updateStatus('Error sending test notification', 'error'); } } diff --git a/server.js b/server.js index 993e7d7..d4d211d 100644 --- a/server.js +++ b/server.js @@ -209,6 +209,53 @@ app.post('/unsubscribe', async (req, res) => { } }); +// Send test notification to all users +app.post('/test-notification', async (req, res) => { + try { + const { message } = req.body; + + if (!pushSubscriptions.length) { + return res.json({ success: false, message: 'No users have notifications enabled' }); + } + + const payload = { + title: '🔔 HikeMap Test Notification', + body: message || 'This is a test notification from HikeMap', + icon: '/icon-192x192.png', + badge: '/icon-72x72.png', + vibrate: [200, 100, 200], + data: { + type: 'test', + timestamp: Date.now() + } + }; + + // Send to all subscriptions + const results = await Promise.allSettled( + pushSubscriptions.map(subscription => + webpush.sendNotification(subscription, JSON.stringify(payload)) + .catch(err => { + if (err.statusCode === 410) { + // Subscription expired, remove it + pushSubscriptions = pushSubscriptions.filter(sub => + sub.endpoint !== subscription.endpoint + ); + } + throw err; + }) + ) + ); + + const successful = results.filter(r => r.status === 'fulfilled').length; + console.log(`Test notification sent to ${successful}/${pushSubscriptions.length} subscribers`); + + res.json({ success: true, sent: successful, total: pushSubscriptions.length }); + } catch (err) { + console.error('Error sending test notification:', err); + res.status(500).json({ error: 'Failed to send test notification' }); + } +}); + // Send notification to a specific user app.post('/send-notification', async (req, res) => { try {