Fix award source round dropdown — auto-resolve competitionId from program
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m19s

Awards created from /admin/awards/new only sent programId, leaving
competitionId null. The edit page's source round dropdown was empty
because it depended on competitionId to fetch competition rounds.

- create mutation: auto-resolve competitionId from program's latest competition
- update mutation: backfill competitionId on save if missing
- get query: backfill competitionId on read for legacy awards
- edit page: use award.competition.rounds directly instead of separate query

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 21:00:20 +01:00
parent 619206c03f
commit 70d24036f9
2 changed files with 55 additions and 15 deletions

View File

@@ -70,12 +70,30 @@ export const specialAwardRouter = router({
},
})
// Auto-resolve competition if missing (legacy awards created without competitionId)
let { competition } = award
if (!competition && award.programId) {
const comp = await ctx.prisma.competition.findFirst({
where: { programId: award.programId },
orderBy: { createdAt: 'desc' },
select: { id: true, name: true, rounds: { select: { id: true, name: true, roundType: true, sortOrder: true }, orderBy: { sortOrder: 'asc' as const } } },
})
if (comp) {
competition = comp
// Backfill competitionId on the award
await ctx.prisma.specialAward.update({
where: { id: input.id },
data: { competitionId: comp.id },
})
}
}
// Count eligible projects
const eligibleCount = await ctx.prisma.awardEligibility.count({
where: { awardId: input.id, eligible: true },
})
return { ...award, eligibleCount }
return { ...award, competition, eligibleCount }
}),
// ─── Admin Mutations ────────────────────────────────────────────────────
@@ -100,6 +118,17 @@ export const specialAwardRouter = router({
})
)
.mutation(async ({ ctx, input }) => {
// Auto-resolve competitionId from program if not provided
let competitionId = input.competitionId
if (!competitionId) {
const comp = await ctx.prisma.competition.findFirst({
where: { programId: input.programId },
orderBy: { createdAt: 'desc' },
select: { id: true },
})
competitionId = comp?.id ?? undefined
}
const maxOrder = await ctx.prisma.specialAward.aggregate({
where: { programId: input.programId },
_max: { sortOrder: true },
@@ -114,7 +143,7 @@ export const specialAwardRouter = router({
useAiEligibility: input.useAiEligibility ?? true,
scoringMode: input.scoringMode,
maxRankedPicks: input.maxRankedPicks,
competitionId: input.competitionId,
competitionId,
evaluationRoundId: input.evaluationRoundId,
juryGroupId: input.juryGroupId,
eligibilityMode: input.eligibilityMode,
@@ -160,6 +189,23 @@ export const specialAwardRouter = router({
)
.mutation(async ({ ctx, input }) => {
const { id, ...rest } = input
// Auto-resolve competitionId if missing on existing award
if (rest.competitionId === undefined) {
const existing = await ctx.prisma.specialAward.findUnique({
where: { id },
select: { competitionId: true, programId: true },
})
if (existing && !existing.competitionId) {
const comp = await ctx.prisma.competition.findFirst({
where: { programId: existing.programId },
orderBy: { createdAt: 'desc' },
select: { id: true },
})
if (comp) rest.competitionId = comp.id
}
}
const award = await ctx.prisma.specialAward.update({
where: { id },
data: rest,