Tovább a tartalomhoz

NotificationStore

A NotificationStore egy globális Svelte 5 store, amely kezeli az értesítések állapotát és a Socket.IO kapcsolatot. Automatikusan fallback-el REST API polling-ra, ha a WebSocket nem elérhető.

A store intelligensen kezeli a kapcsolati problémákat:

  1. Socket.IO kapcsolódás sikeres → Valós idejű értesítések WebSocket-en
  2. Socket.IO kapcsolódás sikertelen → Automatikus polling 30 másodpercenként
  3. Socket.IO kapcsolat megszakad → Automatikus átváltás polling-ra
  4. Socket.IO újrakapcsolódik → Automatikus visszaváltás WebSocket-re
// Automatikus inicializálás
const notificationStore = getNotificationStore();
await notificationStore.connect(userId);
// A store automatikusan:
// 1. Megpróbál Socket.IO-val kapcsolódni
// 2. Ha sikertelen, elindítja a polling-ot
// 3. Betölti az értesítéseket REST API-n keresztül
// 4. 30 másodpercenként frissít, ha nincs WebSocket kapcsolat
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
// Értesítések listája
const notifications = $derived(notificationStore.notifications);
// Olvasatlan értesítések száma
const unreadCount = $derived(notificationStore.unreadCount);
// Socket.IO kapcsolat állapota
const isConnected = $derived(notificationStore.isConnected);
// Aktuális kritikus értesítés (ha van)
const currentCritical = $derived(notificationStore.currentCritical);
// Van-e olvasatlan kritikus értesítés
const hasUnreadCritical = $derived(notificationStore.hasUnreadCritical);
<script>
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
const notifications = $derived(notificationStore.notifications);
const unreadCount = $derived(notificationStore.unreadCount);
</script>
<div>
<p>Olvasatlan értesítések: {unreadCount}</p>
{#each notifications as notification}
<div>
<h3>{notification.title}</h3>
<p>{notification.message}</p>
</div>
{/each}
</div>

Socket.IO kapcsolat inicializálása és értesítések betöltése.

await notificationStore.connect(123);

Automatikusan megtörténik: A hooks.client.ts automatikusan meghívja bejelentkezéskor.

Socket.IO kapcsolat bontása.

notificationStore.disconnect();

Értesítések betöltése REST API-n keresztül.

await notificationStore.loadNotifications();
// Toast megjelenítéssel (dev módban)
await notificationStore.loadNotifications(true);

Automatikusan megtörténik:

  • Inicializáláskor
  • 30 másodpercenként, ha Socket.IO nem elérhető

Értesítések újratöltése toast megjelenítéssel (hasznos dev módban).

await notificationStore.reload();

Értesítés olvasottnak jelölése.

await notificationStore.markAsRead(123);

Hatás:

  • Lokális állapot frissítése
  • REST API hívás
  • Socket.IO emit (ha elérhető)

Összes értesítés olvasottnak jelölése.

await notificationStore.markAllAsRead();

Értesítés törlése.

await notificationStore.deleteNotification(123);

Összes értesítés törlése.

await notificationStore.deleteAllNotifications();

Új értesítés küldése.

await notificationStore.sendNotification({
userId: 123,
title: { hu: 'Teszt', en: 'Test' },
message: { hu: 'Teszt üzenet', en: 'Test message' },
type: 'info'
});

Megjegyzés: Inkább használd a sendNotification függvényt a notificationService-ből.

Egy adott app értesítéseinek lekérése.

const userNotifications = notificationStore.getAppNotifications('users');

Egy adott app olvasatlan értesítéseinek száma.

const unreadCount = notificationStore.getAppUnreadCount('users');

Aktuális kritikus értesítés elismerése (eltávolítás a sorból).

notificationStore.acknowledgeCritical();

Automatikusan megtörténik: A CriticalNotificationDialog komponens meghívja az OK gomb kattintásakor.

Értesítések tömbje, időrendben csökkenő sorrendben.

const notifications: Notification[] = notificationStore.notifications;

Olvasatlan értesítések száma.

const unreadCount: number = notificationStore.unreadCount;

Socket.IO kapcsolat állapota.

const isConnected: boolean = notificationStore.isConnected;

Aktuális kritikus értesítés (első a sorban).

const currentCritical: Notification | null = notificationStore.currentCritical;

Van-e olvasatlan kritikus értesítés.

const hasUnreadCritical: boolean = notificationStore.hasUnreadCritical;

A store automatikusan inicializálódik a hooks.client.ts-ben:

hooks.client.ts
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
export async function handleSession({ data }) {
if (data.user?.id) {
const notificationStore = getNotificationStore();
await notificationStore.connect(parseInt(data.user.id));
}
}
// Új értesítés érkezett
socket.on('notification:new', (notification: Notification) => {
// Hozzáadás a listához
this.state.notifications = [notification, ...this.state.notifications];
this.state.unreadCount++;
// Toast megjelenítése (kivéve critical)
this.showToastNotification(notification);
// Browser értesítés
this.showBrowserNotification(notification);
});
// Olvasatlan számláló frissítése
socket.on('notification:unread-count', (count: number) => {
this.state.unreadCount = count;
});
// 30 másodpercenként polling, ha Socket.IO nem elérhető
setInterval(() => {
if (browser && !this.state.isConnected) {
console.log('[NotificationStore] WebSocket disconnected, polling for notifications');
this.loadNotifications();
}
}, 30000);
private showToastNotification(notification: Notification) {
// Critical értesítések a dialog-ba kerülnek
if (notification.type === 'critical') {
this._criticalQueue = [...this._criticalQueue, notification];
return;
}
// Toast megjelenítése
import('svelte-sonner').then(({ toast }) => {
const toastFn = toast[notification.type] || toast.info;
toastFn(title, {
description: message,
duration: 5000,
action: {
label: 'Megnyitás',
onClick: () => this.openNotificationInApp(notification.id)
}
});
});
}

Értesítések Megjelenítése Listában

Szekció neve “Értesítések Megjelenítése Listában”
<script>
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
const notifications = $derived(notificationStore.notifications);
async function handleMarkAsRead(id: number) {
await notificationStore.markAsRead(id);
}
async function handleDelete(id: number) {
await notificationStore.deleteNotification(id);
}
</script>
<div>
{#each notifications as notification}
<div class:unread={!notification.isRead}>
<h3>{notification.title}</h3>
<p>{notification.message}</p>
<p>{new Date(notification.createdAt).toLocaleString()}</p>
{#if !notification.isRead}
<button onclick={() => handleMarkAsRead(notification.id)}>
Olvasottnak jelölés
</button>
{/if}
<button onclick={() => handleDelete(notification.id)}>
Törlés
</button>
</div>
{/each}
</div>
<script>
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
const unreadCount = $derived(notificationStore.unreadCount);
</script>
<button>
Értesítések
{#if unreadCount > 0}
<span class="badge">{unreadCount}</span>
{/if}
</button>
<script>
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
const appNotifications = $derived(notificationStore.getAppNotifications('users'));
const appUnreadCount = $derived(notificationStore.getAppUnreadCount('users'));
</script>
<div>
<h2>Users App Értesítések ({appUnreadCount} olvasatlan)</h2>
{#each appNotifications as notification}
<div>{notification.message}</div>
{/each}
</div>
<script>
import { getNotificationStore } from '$lib/stores/notificationStore.svelte';
const notificationStore = getNotificationStore();
const isConnected = $derived(notificationStore.isConnected);
</script>
<div class="status">
{#if isConnected}
<span class="online">● Online (WebSocket)</span>
{:else}
<span class="offline">● Offline (Polling)</span>
{/if}
</div>