Fixed notifications VAPID
Build and Publish / Build and Publish Docker Image (push) Successful in 1m26s
Build and Publish / Build and Publish Docker Image (push) Successful in 1m26s
This commit is contained in:
@@ -293,6 +293,7 @@
|
||||
<div class="notification-modal">
|
||||
<h2>{{ t.portal_notifications }}</h2>
|
||||
<p id="notificationText">{{ t.portal_notifications_text }}</p>
|
||||
<p id="notificationStatus" style="display:none;margin-top:0.65rem;font-weight:600;"></p>
|
||||
<div class="notification-actions">
|
||||
<button type="button" class="notification-primary" id="notificationToggle">{{ t.portal_notifications_enable }}</button>
|
||||
<button type="button" onclick="closeNotificationSettings()">✕</button>
|
||||
@@ -328,20 +329,60 @@ renderCalendar();
|
||||
var toggle = document.getElementById('notificationToggle');
|
||||
var registration;
|
||||
var subscription;
|
||||
var status = document.getElementById('notificationStatus');
|
||||
function decodeKey(value) {
|
||||
var padding = '='.repeat((4 - value.length % 4) % 4);
|
||||
var raw = atob((value + padding).replace(/-/g, '+').replace(/_/g, '/'));
|
||||
return Uint8Array.from(raw, function(char) { return char.charCodeAt(0); });
|
||||
}
|
||||
function sameKey(left, right) {
|
||||
if (!left || left.byteLength !== right.byteLength) return false;
|
||||
var a = new Uint8Array(left), b = new Uint8Array(right);
|
||||
return a.every(function(value, index) { return value === b[index]; });
|
||||
}
|
||||
function showStatus(message, error) {
|
||||
status.textContent = message;
|
||||
status.style.display = '';
|
||||
status.style.color = error ? '#b42318' : '#067647';
|
||||
}
|
||||
async function saveSubscription(value) {
|
||||
var payload = value.toJSON();
|
||||
payload.language = '{{ lang.code() }}';
|
||||
var response = await fetch('/client/{{ client.media_token }}/push/subscribe', {
|
||||
method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload)
|
||||
});
|
||||
if (!response.ok) throw new Error('Subscription API returned HTTP ' + response.status);
|
||||
}
|
||||
async function refresh() {
|
||||
if (!('serviceWorker' in navigator) || !('PushManager' in window)) return;
|
||||
if (!('serviceWorker' in navigator) || !('PushManager' in window) || !('Notification' in window)) {
|
||||
toggle.disabled = true;
|
||||
showStatus('{{ t.portal_notifications_unsupported }}', true);
|
||||
return;
|
||||
}
|
||||
registration = await navigator.serviceWorker.register('/service-worker.js');
|
||||
await navigator.serviceWorker.ready;
|
||||
subscription = await registration.pushManager.getSubscription();
|
||||
var expectedKey = decodeKey('{{ vapid_public_key }}');
|
||||
if (subscription && !sameKey(subscription.options.applicationServerKey, expectedKey)) {
|
||||
await subscription.unsubscribe();
|
||||
subscription = null;
|
||||
}
|
||||
if (subscription) {
|
||||
await saveSubscription(subscription);
|
||||
showStatus('{{ t.portal_notifications_active }}', false);
|
||||
}
|
||||
toggle.textContent = subscription ? '{{ t.portal_notifications_disable }}' : '{{ t.portal_notifications_enable }}';
|
||||
}
|
||||
window.openNotificationSettings = function() { document.getElementById('notificationModal').classList.add('open'); refresh().catch(console.error); };
|
||||
window.openNotificationSettings = function() {
|
||||
document.getElementById('notificationModal').classList.add('open');
|
||||
refresh().catch(function(error) {
|
||||
console.error(error);
|
||||
showStatus('{{ t.portal_notifications_error }}', true);
|
||||
});
|
||||
};
|
||||
window.closeNotificationSettings = function() { document.getElementById('notificationModal').classList.remove('open'); };
|
||||
toggle.addEventListener('click', async function() {
|
||||
toggle.disabled = true;
|
||||
try {
|
||||
if (!registration) await refresh();
|
||||
if (subscription) {
|
||||
@@ -361,20 +402,21 @@ renderCalendar();
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: decodeKey('{{ vapid_public_key }}')
|
||||
});
|
||||
var payload = subscription.toJSON();
|
||||
payload.language = '{{ lang.code() }}';
|
||||
var response = await fetch('/client/{{ client.media_token }}/push/subscribe', {
|
||||
method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload)
|
||||
});
|
||||
if (!response.ok) { await subscription.unsubscribe(); subscription = null; throw new Error('subscribe failed'); }
|
||||
closeNotificationSettings();
|
||||
await saveSubscription(subscription);
|
||||
showStatus('{{ t.portal_notifications_active }}', false);
|
||||
}
|
||||
toggle.textContent = subscription ? '{{ t.portal_notifications_disable }}' : '{{ t.portal_notifications_enable }}';
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showStatus('{{ t.portal_notifications_error }}', true);
|
||||
} finally {
|
||||
toggle.disabled = false;
|
||||
}
|
||||
});
|
||||
refresh().catch(console.error);
|
||||
refresh().catch(function(error) {
|
||||
console.error(error);
|
||||
showStatus('{{ t.portal_notifications_error }}', true);
|
||||
});
|
||||
})();
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user