Files
BRETT/app/composables/useNotifications.ts
T
2026-10-03 20:07:49 +02:00

59 lines
2.0 KiB
TypeScript

export interface AppNotification {
id: number
uploadId: string
commentId: number
isRead: boolean
isMention: boolean
createdAt: string
actorName: string
actorColor: string | null
content: string
uploadType: 'image' | 'video' | 'audio' | 'youtube' | 'twitch' | 'link'
url: string
thumbUrl: string | null
}
export function useNotifications() {
const notifications = useState<AppNotification[]>('notifications:list', () => [])
const unreadCount = useState<number>('notifications:unread', () => 0)
const unreadUploadIds = computed(() =>
new Set(notifications.value.filter(n => !n.isRead).map(n => n.uploadId)),
)
async function fetchAll() {
const data = await $fetch<{ notifications: AppNotification[], unreadCount: number }>('/api/notifications')
notifications.value = data.notifications
unreadCount.value = data.unreadCount
}
function addLive(notification: AppNotification, count?: number) {
const existing = notifications.value.some(n => n.uploadId === notification.uploadId && !n.isRead)
notifications.value = [notification, ...notifications.value.filter(n => n.uploadId !== notification.uploadId)].slice(0, 30)
unreadCount.value = count ?? (unreadCount.value + (existing ? 0 : 1))
}
async function markAllRead() {
if (!unreadCount.value) return
unreadCount.value = 0
notifications.value = notifications.value.map(n => ({ ...n, isRead: true }))
await $fetch('/api/notifications/read', { method: 'POST' })
}
async function markRead(id: number) {
const target = notifications.value.find(n => n.id === id)
notifications.value = notifications.value.filter(n => target ? n.uploadId !== target.uploadId : n.id !== id)
if (target && !target.isRead) {
unreadCount.value = Math.max(0, unreadCount.value - 1)
}
await $fetch(`/api/notifications/${id}/read`, { method: 'POST' })
}
function reset() {
notifications.value = []
unreadCount.value = 0
}
return { notifications, unreadCount, unreadUploadIds, fetchAll, addLive, markAllRead, markRead, reset }
}