Fix award source round dropdown — auto-resolve competitionId from program
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m19s
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:
@@ -38,12 +38,8 @@ export default function EditAwardPage({
|
|||||||
const utils = trpc.useUtils()
|
const utils = trpc.useUtils()
|
||||||
const { data: award, isLoading } = trpc.specialAward.get.useQuery({ id: awardId })
|
const { data: award, isLoading } = trpc.specialAward.get.useQuery({ id: awardId })
|
||||||
|
|
||||||
// Fetch competition rounds for source round selector
|
// Rounds come from the award's included competition relation
|
||||||
const competitionId = award?.competitionId
|
const competitionRounds = award?.competition?.rounds ?? []
|
||||||
const { data: competition } = trpc.competition.getById.useQuery(
|
|
||||||
{ id: competitionId! },
|
|
||||||
{ enabled: !!competitionId }
|
|
||||||
)
|
|
||||||
|
|
||||||
const updateAward = trpc.specialAward.update.useMutation({
|
const updateAward = trpc.specialAward.update.useMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -266,9 +262,7 @@ export default function EditAwardPage({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="none">No source round</SelectItem>
|
<SelectItem value="none">No source round</SelectItem>
|
||||||
{competition?.rounds
|
{competitionRounds.map((round) => (
|
||||||
?.sort((a, b) => a.sortOrder - b.sortOrder)
|
|
||||||
.map((round) => (
|
|
||||||
<SelectItem key={round.id} value={round.id}>
|
<SelectItem key={round.id} value={round.id}>
|
||||||
{round.name} ({round.roundType})
|
{round.name} ({round.roundType})
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@@ -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
|
// Count eligible projects
|
||||||
const eligibleCount = await ctx.prisma.awardEligibility.count({
|
const eligibleCount = await ctx.prisma.awardEligibility.count({
|
||||||
where: { awardId: input.id, eligible: true },
|
where: { awardId: input.id, eligible: true },
|
||||||
})
|
})
|
||||||
|
|
||||||
return { ...award, eligibleCount }
|
return { ...award, competition, eligibleCount }
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// ─── Admin Mutations ────────────────────────────────────────────────────
|
// ─── Admin Mutations ────────────────────────────────────────────────────
|
||||||
@@ -100,6 +118,17 @@ export const specialAwardRouter = router({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.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({
|
const maxOrder = await ctx.prisma.specialAward.aggregate({
|
||||||
where: { programId: input.programId },
|
where: { programId: input.programId },
|
||||||
_max: { sortOrder: true },
|
_max: { sortOrder: true },
|
||||||
@@ -114,7 +143,7 @@ export const specialAwardRouter = router({
|
|||||||
useAiEligibility: input.useAiEligibility ?? true,
|
useAiEligibility: input.useAiEligibility ?? true,
|
||||||
scoringMode: input.scoringMode,
|
scoringMode: input.scoringMode,
|
||||||
maxRankedPicks: input.maxRankedPicks,
|
maxRankedPicks: input.maxRankedPicks,
|
||||||
competitionId: input.competitionId,
|
competitionId,
|
||||||
evaluationRoundId: input.evaluationRoundId,
|
evaluationRoundId: input.evaluationRoundId,
|
||||||
juryGroupId: input.juryGroupId,
|
juryGroupId: input.juryGroupId,
|
||||||
eligibilityMode: input.eligibilityMode,
|
eligibilityMode: input.eligibilityMode,
|
||||||
@@ -160,6 +189,23 @@ export const specialAwardRouter = router({
|
|||||||
)
|
)
|
||||||
.mutation(async ({ ctx, input }) => {
|
.mutation(async ({ ctx, input }) => {
|
||||||
const { id, ...rest } = 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({
|
const award = await ctx.prisma.specialAward.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: rest,
|
data: rest,
|
||||||
|
|||||||
Reference in New Issue
Block a user