feat: phase 2 - polls, memories, notifications, stats v0.1.0
- 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>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
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('*')
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user