802712c662
- Seed 33 popular games across 5 platforms via admin API script - Add GameDetailDialog with game info and quick-team button - Update GamesLibrary with game card click to open detail dialog - Update Home hot games to open detail dialog instead of navigating - Rewrite invitation accept: frontend auto-joins team + updates status - Add user status reset on team dissolution (endGame) - Add start game / dissolve buttons to TeamSessionPanel lifecycle - Integrate realtime subscriptions in GroupView and Layout - Add notification store realtime invitation listener - Add placeholder images for game covers and avatars - Remove Go hooks, add JS hooks placeholder + Docker mount Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
117 lines
3.2 KiB
TypeScript
117 lines
3.2 KiB
TypeScript
// src/api/invitations.ts
|
|
import pb from './pocketbase'
|
|
import type { Invitation } from '@/types'
|
|
|
|
// 发送邀请
|
|
export async function sendInvitation(data: {
|
|
to: string
|
|
teamSession: string
|
|
}) {
|
|
const user = pb.authStore.model
|
|
if (!user) throw new Error('未登录')
|
|
|
|
// 检查是否已有待处理邀请
|
|
const existing = await pb.collection('invitations').getList(1, 1, {
|
|
filter: `from="${user.id}" && to="${data.to}" && teamSession="${data.teamSession}" && status="pending"`
|
|
})
|
|
|
|
if (existing.items.length > 0) {
|
|
throw new Error('已有待处理的邀请')
|
|
}
|
|
|
|
return pb.collection('invitations').create({
|
|
...data,
|
|
from: user.id,
|
|
status: 'pending'
|
|
})
|
|
}
|
|
|
|
// 批量发送邀请
|
|
export async function sendBulkInvitations(recipients: string[], teamSessionId: string) {
|
|
const promises = recipients.map(to =>
|
|
sendInvitation({ to, teamSession: teamSessionId })
|
|
)
|
|
|
|
return Promise.allSettled(promises)
|
|
}
|
|
|
|
// 获取用户的待处理邀请
|
|
export async function getPendingInvitations(): Promise<Invitation[]> {
|
|
const user = pb.authStore.model
|
|
if (!user) return []
|
|
|
|
const result = await pb.collection('invitations').getList(1, 50, {
|
|
filter: `to="${user.id}" && status="pending"`,
|
|
sort: '-created',
|
|
expand: 'from,teamSession'
|
|
})
|
|
|
|
return result.items as unknown as Invitation[]
|
|
}
|
|
|
|
// 获取我发送的邀请
|
|
export async function getMySentInvitations(): Promise<Invitation[]> {
|
|
const user = pb.authStore.model
|
|
if (!user) return []
|
|
|
|
const result = await pb.collection('invitations').getList(1, 50, {
|
|
filter: `from="${user.id}"`,
|
|
sort: '-created',
|
|
expand: 'to,teamSession'
|
|
})
|
|
|
|
return result.items as unknown as Invitation[]
|
|
}
|
|
|
|
// 响应邀请
|
|
export async function respondInvitation(
|
|
invitationId: string,
|
|
response: 'accepted' | 'rejected',
|
|
rejectReason?: string
|
|
) {
|
|
const updateData: Record<string, unknown> = {
|
|
status: response
|
|
}
|
|
|
|
if (response === 'rejected' && rejectReason) {
|
|
updateData.rejectReason = rejectReason
|
|
}
|
|
|
|
// 更新邀请状态
|
|
await pb.collection('invitations').update(invitationId, updateData)
|
|
|
|
// 接受邀请:前端处理加入 team session + 更新用户状态
|
|
if (response === 'accepted') {
|
|
const user = pb.authStore.model
|
|
if (!user) return
|
|
|
|
// 获取邀请详情以找到 team session
|
|
const invitation = await pb.collection('invitations').getOne(invitationId) as any
|
|
const teamSessionId = invitation.teamSession
|
|
|
|
// 加入 team session
|
|
const session = await pb.collection('team_sessions').getOne(teamSessionId) as any
|
|
const members: string[] = session.members || []
|
|
if (!members.includes(user.id)) {
|
|
members.push(user.id)
|
|
await pb.collection('team_sessions').update(teamSessionId, { members })
|
|
}
|
|
|
|
// 更新用户状态为 in_team
|
|
await pb.collection('users').update(user.id, { status: 'in_team' })
|
|
}
|
|
}
|
|
|
|
// 订阅邀请变更
|
|
export function subscribeInvitations(callback: (invitation: Invitation) => void) {
|
|
const user = pb.authStore.model
|
|
if (!user) return () => {}
|
|
|
|
return pb.collection('invitations').subscribe('*', (payload) => {
|
|
const invite = payload.record as unknown as Invitation
|
|
if (invite.to === user.id || invite.from === user.id) {
|
|
callback(invite)
|
|
}
|
|
})
|
|
}
|