Files
kashilo/js/services/notifications.js

127 lines
3.2 KiB
JavaScript

/**
* Notifications Service - Polls and manages user notifications
*/
import { directus } from './directus.js'
import { client } from './directus/client.js'
import { auth } from './auth.js'
class NotificationsService {
constructor() {
this.unreadCount = 0
this.notifications = []
this.listeners = new Set()
this.pollTimer = null
this.pollInterval = 60 * 1000 // 60 seconds
this.userHash = null
}
async init() {
if (!auth.isLoggedIn()) return
this.userHash = await this._getUserHash()
if (!this.userHash) return
await this.refresh()
this.startPolling()
}
async _getUserHash() {
const user = await auth.getUser()
return user?.id || null
}
async refresh() {
if (!this.userHash) return
if (!auth.isLoggedIn()) {
this.destroy()
return
}
try {
const [count, notifications] = await Promise.all([
directus.getUnreadCount(this.userHash),
directus.getNotifications(this.userHash)
])
this.unreadCount = count
this.notifications = notifications
this.notify()
} catch (e) {
if (e.status === 401 || e.status === 403) {
this.stopPolling()
}
}
}
startPolling() {
this.stopPolling()
this.pollTimer = setInterval(() => this.refresh(), this.pollInterval)
document.addEventListener('visibilitychange', this._onVisibility)
}
stopPolling() {
if (this.pollTimer) {
clearInterval(this.pollTimer)
this.pollTimer = null
}
document.removeEventListener('visibilitychange', this._onVisibility)
}
_onVisibility = async () => {
if (document.visibilityState === 'visible') {
if (client._refreshPromise) {
await client._refreshPromise
}
this.refresh()
}
}
async markRead(id) {
await directus.markNotificationRead(id)
const n = this.notifications.find(n => n.id === id)
if (n) {
n.read = true
this.unreadCount = Math.max(0, this.unreadCount - 1)
this.notify()
}
}
async markAllRead() {
if (!this.userHash) return
await directus.markAllNotificationsRead(this.userHash)
this.notifications.forEach(n => n.read = true)
this.unreadCount = 0
this.notify()
}
async remove(id) {
await directus.deleteNotification(id)
this.notifications = this.notifications.filter(n => n.id !== id)
this.unreadCount = this.notifications.filter(n => !n.read).length
this.notify()
}
subscribe(callback) {
this.listeners.add(callback)
return () => this.listeners.delete(callback)
}
notify() {
for (const cb of this.listeners) {
cb(this.unreadCount, this.notifications)
}
}
destroy() {
this.stopPolling()
this.listeners.clear()
this.notifications = []
this.unreadCount = 0
this.userHash = null
}
}
export const notificationsService = new NotificationsService()