feat: lunch member reads — getEventForMember + getTeamPicks

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt
2026-04-29 02:33:24 +02:00
parent 9e14775f08
commit d779959e54
2 changed files with 176 additions and 0 deletions

View File

@@ -225,6 +225,70 @@ export const lunchRouter = router({
return { ok: true as const }
}),
// ─── Member reads ────────────────────────────────────────────────────────
/**
* Public-ish event view for the applicant dashboard banner.
* Returns null when the lunch event is disabled (banner hidden).
*/
getEventForMember: protectedProcedure
.input(z.object({ programId: z.string() }))
.query(async ({ ctx, input }) => {
const event = await ctx.prisma.lunchEvent.findUnique({
where: { programId: input.programId },
select: {
id: true,
enabled: true,
eventAt: true,
endAt: true,
venue: true,
notes: true,
changeCutoffHours: true,
},
})
if (!event || !event.enabled) return null
const changeDeadline = event.eventAt
? new Date(event.eventAt.getTime() - event.changeCutoffHours * 3_600_000)
: null
return { ...event, changeDeadline }
}),
/**
* All picks for the caller's team. Within-team transparency: every team
* member sees their teammates' picks (lunch picks aren't sensitive).
* Cross-team and admins go through the manifest endpoint instead, which
* has more detail.
*/
getTeamPicks: protectedProcedure
.input(z.object({ projectId: z.string() }))
.query(async ({ ctx, input }) => {
const userId = ctx.user.id
const role = ctx.user.role
const isAdmin = role === 'SUPER_ADMIN' || role === 'PROGRAM_ADMIN'
if (!isAdmin) {
const tm = await ctx.prisma.teamMember.findFirst({
where: { projectId: input.projectId, userId },
})
if (!tm) throw new TRPCError({ code: 'FORBIDDEN' })
}
const ams = await ctx.prisma.attendingMember.findMany({
where: { confirmation: { projectId: input.projectId } },
include: {
user: { select: { id: true, name: true, email: true } },
lunchPick: { include: { dish: true } },
},
})
return ams.map((am) => ({
attendingMemberId: am.id,
userId: am.user.id,
memberName: am.user.name ?? am.user.email,
dish: am.lunchPick?.dish ?? null,
allergens: am.lunchPick?.allergens ?? [],
allergenOther: am.lunchPick?.allergenOther ?? null,
hasPicked: !!am.lunchPick?.pickedAt,
}))
}),
// ─── Mixed-permission picker ─────────────────────────────────────────────
/**