Pushizo Docs
Rehberler

Vue ile Pushizo Web SDK

@pushizo/web Vue 3'te bir plugin ile başlatılır; bileşenler usePushizo() composable'ı üzerinden SDK'ya, hazır olma durumuna ve abonelik durumuna (reaktif) erişir. Nuxt 3 için yalnızca istemci tarafında çalışan bir…

@pushizo/web Vue 3'te bir plugin ile başlatılır; bileşenler usePushizo() composable'ı üzerinden SDK'ya, hazır olma durumuna ve abonelik durumuna (reaktif) erişir. Nuxt 3 için yalnızca istemci tarafında çalışan bir plugin dosyası yeterlidir.

1. Kurulum

npm install @pushizo/web

Service worker site kökünde: Vite projelerinde public/PushizoSDKWorker.js, Nuxt'ta public/PushizoSDKWorker.js.

// public/PushizoSDKWorker.js
const apiUrl = new URL(self.location.href).searchParams.get('apiUrl') || 'https://api.example.com';
importScripts(`${apiUrl.replace(/\/$/, '')}/sdk-web/PushizoSDKWorker.js`);

Ortam: VITE_HS_APP_ID, VITE_HS_API_URL (Nuxt: NUXT_PUBLIC_HS_APP_ID, NUXT_PUBLIC_HS_API_URL → runtimeConfig.public).

2. Plugin ve composable

// src/pushizo.ts
import { inject, ref, type App, type InjectionKey, type Ref } from 'vue';
import Pushizo, { type PushizoSdk, type InitOptions, type PushSubscriptionState } from '@pushizo/web';

export interface PushizoState {
  sdk: PushizoSdk;
  ready: Ref<boolean>;
  error: Ref<string | null>;
  subscription: Ref<PushSubscriptionState | null>;
}

export const PushizoKey: InjectionKey<PushizoState> = Symbol('pushizo');

export function createPushizo(options: InitOptions) {
  const ready = ref(false);
  const error = ref<string | null>(null);
  const subscription = ref<PushSubscriptionState | null>(null);

  return {
    install(app: App) {
      app.provide(PushizoKey, { sdk: Pushizo, ready, error, subscription });
      if (typeof window === 'undefined') return; // SSR: tarayıcı API'sine dokunma
      Pushizo.User.pushSubscription.addObserver((state) => { subscription.value = state; });
      Pushizo.init(options)
        .then(() => {
          ready.value = true;
          subscription.value = Pushizo.User.pushSubscription.state;
        })
        .catch((err: unknown) => { error.value = err instanceof Error ? err.message : String(err); });
    },
  };
}

export function usePushizo(): PushizoState {
  const state = inject(PushizoKey);
  if (!state) throw new Error('usePushizo, createPushizo plugin’i kurulmadan kullanılamaz');
  return state;
}
// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createPushizo } from './pushizo';

createApp(App)
  .use(
    createPushizo({
      appId: import.meta.env.VITE_HS_APP_ID,
      apiUrl: import.meta.env.VITE_HS_API_URL,
      serviceWorkerPath: '/PushizoSDKWorker.js',
      allowLocalhostAsSecureOrigin: import.meta.env.DEV,
      bell: { enabled: true },
    }),
  )
  .mount('#app');

Nuxt 3

// plugins/pushizo.client.ts — yalnızca istemcide çalışır
import { createPushizo } from '~/pushizo';

export default defineNuxtPlugin((nuxtApp) => {
  const config = useRuntimeConfig();
  nuxtApp.vueApp.use(
    createPushizo({
      appId: config.public.hsAppId,
      apiUrl: config.public.hsApiUrl,
      allowLocalhostAsSecureOrigin: import.meta.dev,
    }),
  );
});

Sunucu tarafında inject çağrılan bileşenler için ready false kalır; SDK'ya dokunan kod ready olana kadar çalışmaz.

3. İzin ve abonelik

<script setup lang="ts">
import { computed } from 'vue';
import { usePushizo } from '@/pushizo';

const { sdk, ready, subscription } = usePushizo();
const permission = computed(() => (ready.value ? sdk.Notifications.permission : 'default'));
</script>

<template>
  <p v-if="!ready">SDK yükleniyor…</p>
  <p v-else-if="permission === 'unsupported'">Bu tarayıcı web push desteklemiyor (HTTPS gerekir).</p>
  <p v-else-if="permission === 'denied'">Bildirimler tarayıcı ayarlarından engellenmiş.</p>
  <button v-else-if="subscription?.optedIn" type="button" @click="sdk.User.pushSubscription.optOut()">Bildirimleri kapat</button>
  <button v-else type="button" @click="sdk.Notifications.requestPermission()">Bildirimlere izin ver</button>
</template>

permission değeri requestPermission sonrasında abonelik gözlemcisi tetiklenince yeniden hesaplanır (subscription değişir).

4. Login / logout

// Pinia store'unuzdaki kullanıcı değişince
import { watch } from 'vue';
import { usePushizo } from '@/pushizo';

const { sdk, ready } = usePushizo();
watch(
  [ready, () => auth.user],
  ([isReady, user]) => {
    if (!isReady) return;
    if (user) void sdk.login(user.id, user.identityHash); // identity_hash sunucudan (zorunluysa)
    else if (sdk.User.externalId) void sdk.logout();
  },
  { immediate: true },
);

5. Tag, olay ve rota takibi

sdk.User.addTags({ plan: 'pro' });
sdk.User.removeTag('plan');
sdk.Session.sendEvent('purchase', { sku: 'A1' }, 49.9);

Vue Router ile in-app screen tetiği:

// src/router.ts
router.afterEach((to) => {
  const { sdk, ready } = usePushizo();
  if (ready.value) sdk.InAppMessages.setScreen(to.name ? String(to.name) : to.path);
});

usePushizo() inject kullandığından bileşen/setup dışında çağrılamaz; router guard'ında app.runWithContext(() => usePushizo()) ya da plugin'in döndürdüğü state'i modül düzeyinde saklayın.

6. Bildirim kutusu bileşeni

<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
import type { InboxItem } from '@pushizo/web';
import { usePushizo } from '@/pushizo';

const { sdk, ready } = usePushizo();
const items = ref<InboxItem[]>([]);
const unread = ref(0);
const loading = ref(false);
const error = ref<string | null>(null);
let stop: (() => void) | null = null;

async function load() {
  loading.value = true;
  try {
    const page = await sdk.Inbox.list({ limit: 20 });
    items.value = page.items;
    unread.value = page.unreadCount;
    error.value = null;
  } catch (e) {
    error.value = e instanceof Error ? e.message : String(e);
  } finally {
    loading.value = false;
  }
}
async function markRead(id: string) {
  const updated = await sdk.Inbox.markRead(id);
  items.value = items.value.map((i) => (i.id === id ? updated : i));
}
async function archive(id: string) {
  await sdk.Inbox.archive(id);
  items.value = items.value.filter((i) => i.id !== id);
}

watch(ready, (r) => { if (r) { void load(); stop = sdk.Inbox.addObserver((e) => { unread.value = e.unreadCount; }); } }, { immediate: true });
onUnmounted(() => stop?.());
</script>

<template>
  <section aria-label="Bildirim kutusu">
    <h2>Bildirimler ({{ unread }} okunmamış)</h2>
    <button type="button" :disabled="loading" @click="load">{{ loading ? 'Yükleniyor…' : 'Yenile' }}</button>
    <button type="button" @click="sdk.Inbox.markAllRead().then(load)">Tümünü okundu işaretle</button>
    <p v-if="error" role="alert">{{ error }}</p>
    <p v-else-if="items.length === 0">Bildirim yok.</p>
    <ul v-else>
      <li v-for="item in items" :key="item.id" :data-read="item.read">
        <strong>{{ item.title ?? '(başlıksız)' }}</strong>
        <p v-if="item.body">{{ item.body }}</p>
        <a v-if="item.url" :href="item.url">Aç</a>
        <button type="button" :disabled="item.read" @click="markRead(item.id)">Okundu</button>
        <button type="button" @click="archive(item.id)">Arşivle</button>
      </li>
    </ul>
  </section>
</template>

7. Bildirim tıklaması

onMounted(() => {
  const off = sdk.Notifications.addClickListener(({ notification, result }) => {
    router.push(result.url ?? notification.url ?? '/');
  });
  onUnmounted(off);
});

8. Sorun giderme

  • window is not defined: plugin SSR'da init çağırıyor; Nuxt'ta dosya adı .client.ts olmalı.
  • Service worker 404 / abonelik oluşmuyor / bildirim gelmiyor: Web SDK sorun giderme.
  • iOS Safari: iOS web push.

Bu sayfada