Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | import {prisma} from './db' import {displayName} from './songs' import {avatarUrl} from './avatars' export type BoardProposal = { id: string title: string artist: string youtubeUrl: string | null lyricsUrl: string | null proposer: string proposerAvatar: string | null proposedAt: string voters: {name: string; avatar: string | null}[] mine: boolean } /** Everything the Proposals page shows, in one query per list. */ export async function getBoard( userId: string, band: {id: string; voteThreshold: number}, ) { const threshold = band.voteThreshold const who = { select: { id: true, name: true, displayName: true, email: true, avatarAt: true, }, } as const const [pending, approved, archived] = await Promise.all([ prisma.proposal.findMany({ where: {bandId: band.id, status: 'PENDING'}, orderBy: {createdAt: 'desc'}, include: { proposer: who, votes: {include: {user: who}, orderBy: {createdAt: 'asc'}}, }, }), prisma.proposal.findMany({ where: {bandId: band.id, status: 'APPROVED'}, orderBy: {updatedAt: 'desc'}, take: 8, }), prisma.proposal.findMany({ where: {bandId: band.id, status: 'ARCHIVED'}, orderBy: {updatedAt: 'desc'}, take: 30, include: {proposer: who}, }), ]) // Link approved proposals to the song they became const songs = await prisma.song.findMany({ where: { bandId: band.id, title: {in: approved.map((a) => a.title), mode: 'insensitive'}, }, select: {id: true, title: true}, }) const songByTitle = new Map(songs.map((s) => [s.title.toLowerCase(), s.id])) const toBoard = (p: (typeof pending)[number]): BoardProposal => ({ id: p.id, title: p.title, artist: p.artist, youtubeUrl: p.youtubeUrl, lyricsUrl: p.lyricsUrl, proposer: displayName(p.proposer), proposerAvatar: avatarUrl(p.proposer), proposedAt: p.createdAt.toISOString(), voters: p.votes.map((v) => ({ name: displayName(v.user), avatar: avatarUrl(v.user), })), mine: p.votes.some((v) => v.userId === userId), }) return { threshold, pending: pending.map(toBoard), approved: approved.map((a) => ({ id: a.id, title: a.title, artist: a.artist, approvedAt: a.updatedAt.toISOString(), songId: songByTitle.get(a.title.toLowerCase()) ?? null, })), archived: archived.map((a) => ({ id: a.id, title: a.title, artist: a.artist, proposer: displayName(a.proposer), })), } } export type Board = Awaited<ReturnType<typeof getBoard>> |