Fix rounds management bugs and invitation flow
- Fix rounds list showing 0 projects by adding _count to program.list query - Fix round reordering by using correct cache invalidation params - Fix finalizeResults to auto-advance passed projects to next round - Fix member list not updating after add/remove by invalidating user.list - Fix invitation link error page by correcting path from /auth-error to /error - Add /apply, /verify, /error to public paths in auth config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -714,11 +714,28 @@ export const filteringRouter = router({
|
||||
|
||||
/**
|
||||
* Finalize filtering results — apply outcomes to project statuses
|
||||
* PASSED → keep in pool, FILTERED_OUT → set aside (NOT deleted)
|
||||
* PASSED → mark as ELIGIBLE and advance to next round
|
||||
* FILTERED_OUT → mark as REJECTED (data preserved)
|
||||
*/
|
||||
finalizeResults: adminProcedure
|
||||
.input(z.object({ roundId: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
// Get current round to find the next one
|
||||
const currentRound = await ctx.prisma.round.findUniqueOrThrow({
|
||||
where: { id: input.roundId },
|
||||
select: { id: true, programId: true, sortOrder: true, name: true },
|
||||
})
|
||||
|
||||
// Find the next round by sortOrder
|
||||
const nextRound = await ctx.prisma.round.findFirst({
|
||||
where: {
|
||||
programId: currentRound.programId,
|
||||
sortOrder: { gt: currentRound.sortOrder },
|
||||
},
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
select: { id: true, name: true },
|
||||
})
|
||||
|
||||
const results = await ctx.prisma.filteringResult.findMany({
|
||||
where: { roundId: input.roundId },
|
||||
})
|
||||
@@ -732,27 +749,45 @@ export const filteringRouter = router({
|
||||
.filter((r) => (r.finalOutcome || r.outcome) === 'PASSED')
|
||||
.map((r) => r.projectId)
|
||||
|
||||
// Update RoundProject statuses
|
||||
await ctx.prisma.$transaction([
|
||||
// Filtered out projects get REJECTED status (data preserved)
|
||||
...(filteredOutIds.length > 0
|
||||
? [
|
||||
ctx.prisma.roundProject.updateMany({
|
||||
where: { roundId: input.roundId, projectId: { in: filteredOutIds } },
|
||||
data: { status: 'REJECTED' },
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
// Passed projects get ELIGIBLE status
|
||||
...(passedIds.length > 0
|
||||
? [
|
||||
ctx.prisma.roundProject.updateMany({
|
||||
where: { roundId: input.roundId, projectId: { in: passedIds } },
|
||||
data: { status: 'ELIGIBLE' },
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
])
|
||||
// Build transaction operations
|
||||
const operations: Prisma.PrismaPromise<unknown>[] = []
|
||||
|
||||
// Filtered out projects get REJECTED status (data preserved)
|
||||
if (filteredOutIds.length > 0) {
|
||||
operations.push(
|
||||
ctx.prisma.roundProject.updateMany({
|
||||
where: { roundId: input.roundId, projectId: { in: filteredOutIds } },
|
||||
data: { status: 'REJECTED' },
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Passed projects get ELIGIBLE status
|
||||
if (passedIds.length > 0) {
|
||||
operations.push(
|
||||
ctx.prisma.roundProject.updateMany({
|
||||
where: { roundId: input.roundId, projectId: { in: passedIds } },
|
||||
data: { status: 'ELIGIBLE' },
|
||||
})
|
||||
)
|
||||
|
||||
// If there's a next round, advance passed projects to it
|
||||
if (nextRound) {
|
||||
operations.push(
|
||||
ctx.prisma.roundProject.createMany({
|
||||
data: passedIds.map((projectId) => ({
|
||||
roundId: nextRound.id,
|
||||
projectId,
|
||||
status: 'SUBMITTED' as const,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute all operations in a transaction
|
||||
await ctx.prisma.$transaction(operations)
|
||||
|
||||
await logAudit({
|
||||
userId: ctx.user.id,
|
||||
@@ -763,10 +798,16 @@ export const filteringRouter = router({
|
||||
action: 'FINALIZE_FILTERING',
|
||||
passed: passedIds.length,
|
||||
filteredOut: filteredOutIds.length,
|
||||
advancedToRound: nextRound?.name || null,
|
||||
},
|
||||
})
|
||||
|
||||
return { passed: passedIds.length, filteredOut: filteredOutIds.length }
|
||||
return {
|
||||
passed: passedIds.length,
|
||||
filteredOut: filteredOutIds.length,
|
||||
advancedToRoundId: nextRound?.id || null,
|
||||
advancedToRoundName: nextRound?.name || null,
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,12 @@ export const programRouter = router({
|
||||
select: { rounds: true },
|
||||
},
|
||||
rounds: input?.includeRounds ? {
|
||||
orderBy: { createdAt: 'asc' },
|
||||
orderBy: { sortOrder: 'asc' },
|
||||
include: {
|
||||
_count: {
|
||||
select: { roundProjects: true, assignments: true },
|
||||
},
|
||||
},
|
||||
} : false,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user