Decouple signup from push service outages
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
"orientation": "portrait",
|
||||
"background_color": "#000000",
|
||||
"theme_color": "#000000",
|
||||
"gcm_sender_id": "103953800507",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/app-icon-192.png",
|
||||
|
||||
11
src/App.vue
11
src/App.vue
@@ -12,7 +12,12 @@ import {
|
||||
loginWithRemoteApp,
|
||||
resumeRemoteAppLogin,
|
||||
} from './services/signer'
|
||||
import { notificationPermission, subscribeToNotifications } from './services/notifications'
|
||||
import {
|
||||
notificationPermission,
|
||||
requestNotificationPermission,
|
||||
subscribeToNotifications,
|
||||
subscribeToNotificationsInBackground,
|
||||
} from './services/notifications'
|
||||
|
||||
const heroBackgrounds = Object.entries(
|
||||
import.meta.glob('../public/images/bg-*.{avif,webp,jpg,jpeg,png}', {
|
||||
@@ -1042,8 +1047,9 @@ const createMembership = async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
await subscribeToNotifications()
|
||||
await requestNotificationPermission()
|
||||
signupNotificationsEnabled.value = true
|
||||
subscribeToNotificationsInBackground()
|
||||
} catch (error) {
|
||||
formError.value = error instanceof Error ? error.message : 'Could not enable notifications.'
|
||||
isCreatingMembership.value = false
|
||||
@@ -2116,6 +2122,7 @@ onMounted(async () => {
|
||||
saveSignupDraft()
|
||||
openSignup()
|
||||
}
|
||||
subscribeToNotificationsInBackground()
|
||||
window.addEventListener('popstate', () => {
|
||||
currentPath.value = window.location.pathname
|
||||
})
|
||||
|
||||
@@ -19,6 +19,17 @@ export const notificationSupport = () => ({
|
||||
secure: window.isSecureContext || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1',
|
||||
})
|
||||
|
||||
export const requestNotificationPermission = async () => {
|
||||
if (!('Notification' in window)) throw new Error('Notifications are not supported in this browser.')
|
||||
const support = notificationSupport()
|
||||
if (!support.secure) throw new Error('Notifications require HTTPS.')
|
||||
const requested = Notification.permission === 'granted' ? 'granted' : await Notification.requestPermission()
|
||||
permission.value = requested
|
||||
if (requested !== 'granted') throw new Error('Notification permission was not granted.')
|
||||
if ('serviceWorker' in navigator) await navigator.serviceWorker.register('/sw.js', { scope: '/' }).catch(() => null)
|
||||
return true
|
||||
}
|
||||
|
||||
const saveSubscription = async (subscription) => {
|
||||
const response = await fetch('/api/notifications/subscribe', {
|
||||
method: 'POST',
|
||||
@@ -38,7 +49,7 @@ const sameApplicationServerKey = (subscription, applicationServerKey) => {
|
||||
return existingBytes.every((byte, index) => byte === applicationServerKey[index])
|
||||
}
|
||||
|
||||
export const subscribeToNotifications = async () => {
|
||||
export const subscribeToNotifications = async ({ requestPermission = true } = {}) => {
|
||||
const support = notificationSupport()
|
||||
if (!support.supported) throw new Error('Push notifications are not supported in this browser.')
|
||||
if (!support.secure) throw new Error('Push notifications require HTTPS.')
|
||||
@@ -49,9 +60,8 @@ export const subscribeToNotifications = async () => {
|
||||
if (!keyData.configured) throw new Error('VAPID private key is not configured on the server.')
|
||||
const applicationServerKey = urlBase64ToUint8Array(keyData.publicKey)
|
||||
|
||||
const requested = Notification.permission === 'granted' ? 'granted' : await Notification.requestPermission()
|
||||
permission.value = requested
|
||||
if (requested !== 'granted') throw new Error('Notification permission was not granted.')
|
||||
if (requestPermission) await requestNotificationPermission()
|
||||
else if (Notification.permission !== 'granted') throw new Error('Notification permission was not granted.')
|
||||
|
||||
await navigator.serviceWorker.register('/sw.js', { scope: '/' })
|
||||
const registration = await navigator.serviceWorker.ready
|
||||
@@ -67,3 +77,19 @@ export const subscribeToNotifications = async () => {
|
||||
})
|
||||
return saveSubscription(subscription)
|
||||
}
|
||||
|
||||
export const subscribeToNotificationsInBackground = ({ attempts = 8 } = {}) => {
|
||||
if (!('Notification' in window) || Notification.permission !== 'granted') return
|
||||
const delays = [0, 2000, 5000, 10000, 20000, 45000, 90000, 180000]
|
||||
const run = (attempt = 0) => {
|
||||
window.setTimeout(async () => {
|
||||
try {
|
||||
await subscribeToNotifications({ requestPermission: false })
|
||||
} catch (error) {
|
||||
console.warn('Notification push registration retry failed:', error instanceof Error ? error.message : error)
|
||||
if (attempt + 1 < attempts) run(attempt + 1)
|
||||
}
|
||||
}, delays[Math.min(attempt, delays.length - 1)])
|
||||
}
|
||||
run()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user