story-research-zapwall/hooks/useNotifications.ts
2026-01-10 10:50:47 +01:00

137 lines
4.7 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react'
import { notificationService } from '@/lib/notificationService'
import type { Notification } from '@/lib/notificationService'
const MAX_NOTIFICATIONS = 100
const POLL_INTERVAL_MS = 30_000
export function useNotifications(userPubkey: string | null): {
notifications: Notification[]
unreadCount: number
loading: boolean
markAsRead: (notificationId: string) => void
markAllAsRead: () => void
deleteNotification: (notificationId: string) => void
} {
const [notifications, setNotifications] = useState<Notification[]>([])
const [loading, setLoading] = useState(true)
useNotificationsPoller({ userPubkey, setNotifications, setLoading })
const effectiveNotifications = userPubkey ? notifications : []
const effectiveLoading = userPubkey ? loading : false
const unreadCount = effectiveNotifications.filter((n) => !n.read).length
const actions = useNotificationActions({ userPubkey, setNotifications })
return {
notifications: effectiveNotifications,
unreadCount,
loading: effectiveLoading,
markAsRead: actions.markAsRead,
markAllAsRead: actions.markAllAsRead,
deleteNotification: actions.deleteNotification,
}
}
function useNotificationsPoller(params: {
userPubkey: string | null
setNotifications: (value: Notification[]) => void
setLoading: (value: boolean) => void
}): void {
useEffect(() => {
if (!params.userPubkey) {
return
}
void loadAndSetNotifications({ setNotifications: params.setNotifications, setLoading: params.setLoading })
const interval = setInterval(() => {
void loadAndSetNotifications({ setNotifications: params.setNotifications, setLoading: params.setLoading })
}, POLL_INTERVAL_MS)
return () => clearInterval(interval)
}, [params.userPubkey, params.setNotifications, params.setLoading])
}
function useNotificationActions(params: {
userPubkey: string | null
setNotifications: (value: Notification[]) => void
}): {
markAsRead: (notificationId: string) => void
markAllAsRead: () => void
deleteNotification: (notificationId: string) => void
} {
const markAsRead = useCallback((notificationId: string): void => {
if (!params.userPubkey) {
return
}
void markAsReadAndRefresh({ notificationId, setNotifications: params.setNotifications })
}, [params.userPubkey, params.setNotifications])
const markAllAsRead = useCallback((): void => {
if (!params.userPubkey) {
return
}
void markAllAsReadAndRefresh({ setNotifications: params.setNotifications })
}, [params.userPubkey, params.setNotifications])
const deleteNotification = useCallback((notificationId: string): void => {
if (!params.userPubkey) {
return
}
void deleteNotificationAndRefresh({ notificationId, setNotifications: params.setNotifications })
}, [params.userPubkey, params.setNotifications])
return { markAsRead, markAllAsRead, deleteNotification }
}
async function loadAndSetNotifications(params: {
setNotifications: (value: Notification[]) => void
setLoading: (value: boolean) => void
}): Promise<void> {
try {
params.setLoading(true)
params.setNotifications(await notificationService.getAllNotifications(MAX_NOTIFICATIONS))
} catch (error) {
console.error('[useNotifications] Error loading notifications:', error)
} finally {
params.setLoading(false)
}
}
async function refreshNotifications(params: { setNotifications: (value: Notification[]) => void }): Promise<void> {
params.setNotifications(await notificationService.getAllNotifications(MAX_NOTIFICATIONS))
}
async function markAsReadAndRefresh(params: {
notificationId: string
setNotifications: (value: Notification[]) => void
}): Promise<void> {
try {
await notificationService.markAsRead(params.notificationId)
await refreshNotifications({ setNotifications: params.setNotifications })
} catch (error) {
console.error('[useNotifications] Error marking notification as read:', error)
}
}
async function markAllAsReadAndRefresh(params: {
setNotifications: (value: Notification[]) => void
}): Promise<void> {
try {
await notificationService.markAllAsRead()
await refreshNotifications({ setNotifications: params.setNotifications })
} catch (error) {
console.error('[useNotifications] Error marking all as read:', error)
}
}
async function deleteNotificationAndRefresh(params: {
notificationId: string
setNotifications: (value: Notification[]) => void
}): Promise<void> {
try {
await notificationService.deleteNotification(params.notificationId)
await refreshNotifications({ setNotifications: params.setNotifications })
} catch (error) {
console.error('[useNotifications] Error deleting notification:', error)
}
}