c5d3ac01ca
- Group polls with option/rollcall modes, edit by creator, auto-settle - Multimedia memories with upload, preview, inline video playback - In-app notifications for poll/team/group events - Points system and group stats dashboard - Group detail tabs with icons (activity/polls/memories/stats) - Fix: nginx file upload size, static cache blocking API, timezone, auto-cancel Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import { pb } from './pocketbase'
|
|
import type { AppNotification } from '@/types'
|
|
|
|
export async function listNotifications(options?: {
|
|
page?: number
|
|
limit?: number
|
|
unreadOnly?: boolean
|
|
}): Promise<{ items: AppNotification[], total: number }> {
|
|
const { page = 1, limit = 50, unreadOnly = false } = options || {}
|
|
const user = pb.authStore.model
|
|
if (!user) return { items: [], total: 0 }
|
|
|
|
let filter = `user="${user.id}"`
|
|
if (unreadOnly) filter += ' && read=false'
|
|
|
|
const result = await pb.collection('notifications').getList(page, limit, {
|
|
filter,
|
|
sort: '-created'
|
|
})
|
|
return { items: result.items as unknown as AppNotification[], total: result.totalItems }
|
|
}
|
|
|
|
export async function markAsRead(notificationId: string): Promise<AppNotification> {
|
|
return pb.collection('notifications').update(notificationId, { read: true }) as unknown as Promise<AppNotification>
|
|
}
|
|
|
|
export async function markAllAsRead(): Promise<void> {
|
|
const user = pb.authStore.model
|
|
if (!user) return
|
|
|
|
let page = 1
|
|
const batchSize = 50
|
|
let hasMore = true
|
|
|
|
while (hasMore) {
|
|
const result = await pb.collection('notifications').getList(page, batchSize, {
|
|
filter: `user="${user.id}" && read=false`
|
|
})
|
|
|
|
if (result.items.length === 0) break
|
|
|
|
await Promise.all(
|
|
result.items.map(item => pb.collection('notifications').update(item.id, { read: true }))
|
|
)
|
|
|
|
hasMore = result.items.length === batchSize && page * batchSize < result.totalItems
|
|
page++
|
|
}
|
|
}
|
|
|
|
export async function deleteNotification(notificationId: string): Promise<void> {
|
|
await pb.collection('notifications').delete(notificationId)
|
|
}
|
|
|
|
export async function batchDelete(notificationIds: string[]): Promise<void> {
|
|
const batchSize = 20
|
|
for (let i = 0; i < notificationIds.length; i += batchSize) {
|
|
const batch = notificationIds.slice(i, i + batchSize)
|
|
await Promise.all(batch.map(id => pb.collection('notifications').delete(id)))
|
|
}
|
|
}
|
|
|
|
export async function createNotification(data: {
|
|
user: string
|
|
type: string
|
|
title: string
|
|
content?: string
|
|
relatedId?: string
|
|
relatedType?: string
|
|
}): Promise<AppNotification> {
|
|
return pb.collection('notifications').create(data) as unknown as Promise<AppNotification>
|
|
}
|
|
|
|
export async function subscribeNotifications(
|
|
callback: (data: { action: string, record: AppNotification }) => void
|
|
): Promise<() => void> {
|
|
const user = pb.authStore.model
|
|
if (!user) return () => {}
|
|
|
|
await pb.collection('notifications').subscribe('*', (e) => {
|
|
if (e.record?.user === user.id) {
|
|
callback({ action: e.action, record: e.record as unknown as AppNotification })
|
|
}
|
|
})
|
|
|
|
return () => {
|
|
pb.collection('notifications').unsubscribe('*')
|
|
}
|
|
}
|