<template>
<div class="notifications-panel">
<h2 class="notifications-title">Notifications</h2>
<p class="notifications-description">
Push notifications let Navi ping you when a reply is ready — even when the
tab is closed. You get one notification per finished reply, but only when
no Navi window is open on that session.
</p>
<div v-if="!supported" class="notifications-unsupported">
<i class="ph ph-info"></i>
<span>
This browser does not support web push (needs HTTPS, a service worker
and the Push API). Try Chrome or a recent Firefox.
</span>
</div>
<div v-else class="notifications-row">
<div class="notifications-row-text">
<div class="notifications-row-title">Push notifications</div>
<div class="notifications-row-status">
<template v-if="subscribed">Enabled — this device is subscribed.</template>
<template v-else-if="permission === 'denied'">Blocked in browser site settings.</template>
<template v-else>Disabled.</template>
</div>
</div>
<GnSwitch
:model-value="subscribed"
:disabled="busy || permission === 'denied'"
@update:model-value="onToggle"
/>
</div>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { usePush } from '@/composables/usePush.js'
import { useToast } from 'gnexus-ui-kit/vue'
const { supported, permission, subscribed, busy, enable, disable, syncState } = usePush()
const toast = useToast()
onMounted(() => {
syncState()
})
async function onToggle(want) {
try {
if (want) {
const ok = await enable()
if (ok === false && permission.value === 'denied') {
toast.error({ title: 'Permission denied', text: 'Allow notifications in the browser site settings.' })
} else if (ok === false) {
toast.error({ title: 'Push unavailable', text: 'The server does not accept push subscriptions right now.' })
}
} else {
await disable()
}
} catch (err) {
toast.error({ title: 'Push error', text: err.message })
}
}
</script>
<style scoped lang="scss">
.notifications-panel {
max-width: 800px;
margin-bottom: 24px;
}
.notifications-title {
font-size: 1.1rem;
font-weight: 600;
margin: 0 0 12px;
color: var(--color-text, #a9b1d6);
}
.notifications-description {
margin: 0 0 16px;
font-size: 0.875rem;
color: var(--color-text-secondary, #a9b1d6);
}
.notifications-unsupported {
display: flex;
align-items: flex-start;
gap: 8px;
padding: 12px;
border: 1px solid var(--color-border, #3b4261);
border-radius: 8px;
color: var(--color-text-dark, #787c99);
font-size: 0.875rem;
i {
font-size: 16px;
flex-shrink: 0;
}
}
.notifications-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 14px 16px;
border: 1px solid var(--color-border, #3b4261);
border-radius: 8px;
}
.notifications-row-title {
font-size: 0.9rem;
color: var(--color-text, #a9b1d6);
}
.notifications-row-status {
font-size: 0.8rem;
color: var(--color-text-dark, #787c99);
margin-top: 2px;
}
</style>