feat: lunch member reads — getEventForMember + getTeamPicks
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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 ─────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user