Newer
Older
navi-1 / webclient / src / components / settings / NotificationSettingsPanel.vue
<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>