forked from Mirrors/elk
fix: push notification request permission (#677)
This commit is contained in:
parent
6c38477bc2
commit
d8abea75aa
8 changed files with 123 additions and 35 deletions
|
@ -7,11 +7,16 @@ defineProps<{
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits(['hide', 'subscribe'])
|
defineEmits(['hide', 'subscribe'])
|
||||||
|
|
||||||
|
defineSlots<{
|
||||||
|
error: {}
|
||||||
|
}>()
|
||||||
|
|
||||||
const isLegacyAccount = computed(() => !currentUser.value?.vapidKey)
|
const isLegacyAccount = computed(() => !currentUser.value?.vapidKey)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div flex="~ col" role="alert" aria-labelledby="notifications-warning" :class="withHeader ? 'border-b border-base' : null">
|
<div flex="~ col" gap-y-2 role="alert" aria-labelledby="notifications-warning" :class="withHeader ? 'border-b border-base' : null">
|
||||||
<header v-if="withHeader" flex items-center pb-2>
|
<header v-if="withHeader" flex items-center pb-2>
|
||||||
<h2 id="notifications-warning" text-md font-bold w-full>
|
<h2 id="notifications-warning" text-md font-bold w-full>
|
||||||
{{ $t('notification.settings.warning.enable_title') }}
|
{{ $t('notification.settings.warning.enable_title') }}
|
||||||
|
@ -43,5 +48,6 @@ const isLegacyAccount = computed(() => !currentUser.value?.vapidKey)
|
||||||
<span aria-hidden="true" :class="busy && animate ? 'i-ri:loader-2-fill animate-spin' : 'i-ri:check-line'" />
|
<span aria-hidden="true" :class="busy && animate ? 'i-ri:loader-2-fill animate-spin' : 'i-ri:check-line'" />
|
||||||
{{ $t('notification.settings.warning.enable_desktop') }}
|
{{ $t('notification.settings.warning.enable_desktop') }}
|
||||||
</button>
|
</button>
|
||||||
|
<slot v-if="showReAuthMessage" name="error" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{ show: boolean }>()
|
import NotificationSubscribePushNotificationError
|
||||||
|
from '~/components/notification/NotificationSubscribePushNotificationError.vue'
|
||||||
|
|
||||||
let busy = $ref<boolean>(false)
|
defineProps<{ show: boolean }>()
|
||||||
let animateSave = $ref<boolean>(false)
|
|
||||||
let animateSubscription = $ref<boolean>(false)
|
|
||||||
let animateRemoveSubscription = $ref<boolean>(false)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
pushNotificationData,
|
pushNotificationData,
|
||||||
|
@ -18,9 +16,17 @@ const {
|
||||||
subscribe,
|
subscribe,
|
||||||
unsubscribe,
|
unsubscribe,
|
||||||
} = usePushManager()
|
} = usePushManager()
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const pwaEnabled = useRuntimeConfig().public.pwaEnabled
|
const pwaEnabled = useRuntimeConfig().public.pwaEnabled
|
||||||
|
|
||||||
|
let busy = $ref<boolean>(false)
|
||||||
|
let animateSave = $ref<boolean>(false)
|
||||||
|
let animateSubscription = $ref<boolean>(false)
|
||||||
|
let animateRemoveSubscription = $ref<boolean>(false)
|
||||||
|
let subscribeError = $ref<string>('')
|
||||||
|
let showSubscribeError = $ref<boolean>(false)
|
||||||
|
|
||||||
const hideNotification = () => {
|
const hideNotification = () => {
|
||||||
const key = currentUser.value?.account?.acct
|
const key = currentUser.value?.account?.acct
|
||||||
if (key)
|
if (key)
|
||||||
|
@ -63,10 +69,15 @@ const doSubscribe = async () => {
|
||||||
animateSubscription = true
|
animateSubscription = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const subscription = await subscribe()
|
const result = await subscribe()
|
||||||
// todo: apply some logic based on the result: subscription === 'subscribed'
|
if (result !== 'subscribed') {
|
||||||
// todo: maybe throwing an error instead just a literal to show a dialog with the error
|
subscribeError = t(`notification.settings.subscription_error.${result === 'notification-denied' ? 'permission_denied' : 'request_error'}`)
|
||||||
// todo: handle error
|
showSubscribeError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
subscribeError = t('notification.settings.subscription_error.request_error')
|
||||||
|
showSubscribeError = true
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
busy = false
|
busy = false
|
||||||
|
@ -162,7 +173,16 @@ onActivated(() => (busy = false))
|
||||||
:show-re-auth-message="!showWarning"
|
:show-re-auth-message="!showWarning"
|
||||||
@hide="hideNotification"
|
@hide="hideNotification"
|
||||||
@subscribe="doSubscribe"
|
@subscribe="doSubscribe"
|
||||||
/>
|
>
|
||||||
|
<template #error>
|
||||||
|
<Transition name="slide-down">
|
||||||
|
<NotificationSubscribePushNotificationError
|
||||||
|
v-model="showSubscribeError"
|
||||||
|
:message="subscribeError"
|
||||||
|
/>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
</NotificationEnablePushNotification>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<p v-else role="alert" aria-labelledby="notifications-unsupported">
|
<p v-else role="alert" aria-labelledby="notifications-unsupported">
|
||||||
|
@ -172,7 +192,7 @@ onActivated(() => (busy = false))
|
||||||
</Transition>
|
</Transition>
|
||||||
<NotificationEnablePushNotification
|
<NotificationEnablePushNotification
|
||||||
v-if="showWarning"
|
v-if="showWarning"
|
||||||
:show-re-auth-message="true"
|
show-re-auth-message
|
||||||
with-header
|
with-header
|
||||||
px5
|
px5
|
||||||
py4
|
py4
|
||||||
|
@ -180,6 +200,15 @@ onActivated(() => (busy = false))
|
||||||
:busy="busy"
|
:busy="busy"
|
||||||
@hide="hideNotification"
|
@hide="hideNotification"
|
||||||
@subscribe="doSubscribe"
|
@subscribe="doSubscribe"
|
||||||
/>
|
>
|
||||||
|
<template #error>
|
||||||
|
<Transition name="slide-down">
|
||||||
|
<NotificationSubscribePushNotificationError
|
||||||
|
v-model="showSubscribeError"
|
||||||
|
:message="subscribeError"
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
</NotificationEnablePushNotification>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
title?: string
|
||||||
|
message: string
|
||||||
|
}>()
|
||||||
|
const { modelValue } = defineModel<{
|
||||||
|
modelValue: boolean
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="modelValue"
|
||||||
|
role="alert"
|
||||||
|
aria-describedby="notification-failed"
|
||||||
|
flex="~ col"
|
||||||
|
gap-1 text-sm
|
||||||
|
pt-1 ps-2 pe-1 pb-2
|
||||||
|
text-red-600 dark:text-red-400
|
||||||
|
border="~ base rounded red-600 dark:red-400"
|
||||||
|
>
|
||||||
|
<head id="notification-failed" flex justify-between>
|
||||||
|
<div flex items-center gap-x-2 font-bold>
|
||||||
|
<div aria-hidden="true" i-ri:error-warning-fill />
|
||||||
|
<p>{{ title ?? $t('notification.settings.subscription_error.title') }}</p>
|
||||||
|
</div>
|
||||||
|
<CommonTooltip placement="bottom" :content="$t('notification.settings.subscription_error.clear_error')">
|
||||||
|
<button
|
||||||
|
flex rounded-4 p1
|
||||||
|
hover:bg-active cursor-pointer transition-100
|
||||||
|
:aria-label="$t('notification.settings.subscription_error.clear_error')"
|
||||||
|
@click="modelValue = false"
|
||||||
|
>
|
||||||
|
<span aria-hidden="true" w-1.75em h-1.75em i-ri:close-line />
|
||||||
|
</button>
|
||||||
|
</CommonTooltip>
|
||||||
|
</head>
|
||||||
|
<p>{{ message }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -2,7 +2,7 @@ import type { Emoji, PushSubscription as MastoPushSubscription, PushSubscription
|
||||||
|
|
||||||
import type { UserLogin } from '~/types'
|
import type { UserLogin } from '~/types'
|
||||||
|
|
||||||
export type SubscriptionResult = 'subscribed' | 'notification-denied' | 'invalid-state'
|
export type SubscriptionResult = 'subscribed' | 'notification-denied' | 'not-supported' | 'invalid-vapid-key' | 'no-user'
|
||||||
export interface PushManagerSubscriptionInfo {
|
export interface PushManagerSubscriptionInfo {
|
||||||
registration: ServiceWorkerRegistration
|
registration: ServiceWorkerRegistration
|
||||||
subscription: PushSubscription | null
|
subscription: PushSubscription | null
|
||||||
|
|
|
@ -59,33 +59,28 @@ export const usePushManager = () => {
|
||||||
}
|
}
|
||||||
}, { immediate: true, flush: 'post' })
|
}, { immediate: true, flush: 'post' })
|
||||||
|
|
||||||
const subscribe = async (notificationData?: CreatePushNotification, policy?: SubscriptionPolicy, force?: boolean): Promise<SubscriptionResult> => {
|
const subscribe = async (
|
||||||
if (!isSupported || !currentUser.value)
|
notificationData?: CreatePushNotification,
|
||||||
return 'invalid-state'
|
policy?: SubscriptionPolicy,
|
||||||
|
force?: boolean,
|
||||||
|
): Promise<SubscriptionResult> => {
|
||||||
|
if (!isSupported)
|
||||||
|
return 'not-supported'
|
||||||
|
|
||||||
|
if (!currentUser.value)
|
||||||
|
return 'no-user'
|
||||||
|
|
||||||
const { pushSubscription, server, token, vapidKey, account: { acct } } = currentUser.value
|
const { pushSubscription, server, token, vapidKey, account: { acct } } = currentUser.value
|
||||||
|
|
||||||
if (!token || !server || !vapidKey)
|
if (!token || !server || !vapidKey)
|
||||||
return 'invalid-state'
|
return 'invalid-vapid-key'
|
||||||
|
|
||||||
let permission: PermissionState | undefined
|
// always request permission, browsers should remember user decision
|
||||||
|
const permission = await Promise.resolve(Notification.requestPermission()).then((p) => {
|
||||||
|
return p === 'default' ? 'prompt' : p
|
||||||
|
})
|
||||||
|
|
||||||
if (!notificationPermission.value || (notificationPermission.value === 'prompt' && !hiddenNotification.value[acct])) {
|
if (permission === 'denied') {
|
||||||
// safari 16 does not support navigator.permissions.query for notifications
|
|
||||||
// try {
|
|
||||||
// permission = (await navigator.permissions?.query({ name: 'notifications' }))?.state
|
|
||||||
// }
|
|
||||||
// catch {
|
|
||||||
permission = await Promise.resolve(Notification.requestPermission()).then((p: NotificationPermission) => {
|
|
||||||
return p === 'default' ? 'prompt' : p
|
|
||||||
})
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
permission = notificationPermission.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!permission || permission === 'denied') {
|
|
||||||
notificationPermission.value = permission
|
notificationPermission.value = permission
|
||||||
return 'notification-denied'
|
return 'notification-denied'
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,6 +179,12 @@
|
||||||
},
|
},
|
||||||
"save_settings": "Save settings changes",
|
"save_settings": "Save settings changes",
|
||||||
"show_btn": "Show push notifications settings",
|
"show_btn": "Show push notifications settings",
|
||||||
|
"subscription_error": {
|
||||||
|
"clear_error": "Clear error",
|
||||||
|
"permission_denied": "Permission denied: enable notifications in your browser.",
|
||||||
|
"request_error": "An error occurred while requesting the subscription, try again and if the error persists, please report the issue to the Elk repository.",
|
||||||
|
"title": "Could not subscribe to push notifications"
|
||||||
|
},
|
||||||
"title": "Push notifications settings",
|
"title": "Push notifications settings",
|
||||||
"undo_settings": "Undo settings changes",
|
"undo_settings": "Undo settings changes",
|
||||||
"unsubscribe": "Disable push notifications",
|
"unsubscribe": "Disable push notifications",
|
||||||
|
|
|
@ -179,6 +179,12 @@
|
||||||
},
|
},
|
||||||
"save_settings": "Save settings changes",
|
"save_settings": "Save settings changes",
|
||||||
"show_btn": "Show push notifications settings",
|
"show_btn": "Show push notifications settings",
|
||||||
|
"subscription_error": {
|
||||||
|
"clear_error": "Clear error",
|
||||||
|
"permission_denied": "Permission denied: enable notifications in your browser.",
|
||||||
|
"request_error": "An error occurred while requesting the subscription, try again and if the error persists, please report the issue to the Elk repository.",
|
||||||
|
"title": "Could not subscribe to push notifications"
|
||||||
|
},
|
||||||
"title": "Push notifications settings",
|
"title": "Push notifications settings",
|
||||||
"undo_settings": "Undo settings changes",
|
"undo_settings": "Undo settings changes",
|
||||||
"unsubscribe": "Disable push notifications",
|
"unsubscribe": "Disable push notifications",
|
||||||
|
|
|
@ -174,6 +174,12 @@
|
||||||
},
|
},
|
||||||
"save_settings": "Guardar cambios",
|
"save_settings": "Guardar cambios",
|
||||||
"show_btn": "Mostrar ajustes de las notificaciones push",
|
"show_btn": "Mostrar ajustes de las notificaciones push",
|
||||||
|
"subscription_error": {
|
||||||
|
"clear_error": "Limpiar error",
|
||||||
|
"permission_denied": "Permiso denegado: habilite las notificaciones en su navegador.",
|
||||||
|
"request_error": "Se produjo un error al solicitar la suscripción, inténtalo de nuevo y si el error persiste, notifique la incidencia en el repositorio de Elk.",
|
||||||
|
"title": "No se pudo suscribir a las notificaciones push"
|
||||||
|
},
|
||||||
"title": "Ajustes de notificaciones push",
|
"title": "Ajustes de notificaciones push",
|
||||||
"undo_settings": "Deshacer cambios",
|
"undo_settings": "Deshacer cambios",
|
||||||
"unsubscribe": "Cancelar notificaciones push",
|
"unsubscribe": "Cancelar notificaciones push",
|
||||||
|
|
Loading…
Reference in a new issue