fix(mentor): restore Add Project on mentoring rounds + gate mentor assignment
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m15s
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m15s
Three related bugs around the mentoring-round Projects tab: 1. Add Project to Round was unreachable on MENTORING rounds — the table swap in the prior commit lost the button. Export AddProjectDialog from project-states-table and render it inside MentoringProjectsTable with an "Add" button in the filter row and a CTA in the empty state. 2. The "Assign Projects" quick action on the round overview linked to the global pool with an opaque filter; on MENTORING rounds it now switches to the Projects tab where the new Add Project button + auto-fill + per-team picker all live. Non-mentoring rounds keep the old behavior. 3. mentor.assign and mentor.bulkAssign now refuse projects that aren't enrolled in any MENTORING round (any status). The single-assign throws BAD_REQUEST with a guidance message; the bulk path filters them out and reports ineligibleProjectCount in the result so the UI can warn the admin instead of silently skipping. Tests: the multi-mentor-assignment suite now sets up a MENTORING round + ProjectRoundState for each project it tests against, matching the new gate.
This commit is contained in:
@@ -370,6 +370,25 @@ export const mentorRouter = router({
|
||||
where: { id: input.projectId },
|
||||
})
|
||||
|
||||
// Gate: the project MUST be in a MENTORING round (any status, including
|
||||
// DRAFT, ACTIVE, or CLOSED). We do not allow mentor assignment for
|
||||
// projects that aren't part of a mentoring round — those should be
|
||||
// added to a mentoring round first.
|
||||
const inMentoringRound = await ctx.prisma.projectRoundState.findFirst({
|
||||
where: {
|
||||
projectId: input.projectId,
|
||||
round: { roundType: 'MENTORING' },
|
||||
},
|
||||
select: { id: true },
|
||||
})
|
||||
if (!inMentoringRound) {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message:
|
||||
'This project is not in a mentoring round. Add it to a mentoring round first, then assign mentors.',
|
||||
})
|
||||
}
|
||||
|
||||
// Verify mentor exists
|
||||
const mentor = await ctx.prisma.user.findUniqueOrThrow({
|
||||
where: { id: input.mentorId },
|
||||
@@ -704,7 +723,13 @@ export const mentorRouter = router({
|
||||
}
|
||||
|
||||
const projects = await ctx.prisma.project.findMany({
|
||||
where: { id: { in: input.projectIds } },
|
||||
where: {
|
||||
id: { in: input.projectIds },
|
||||
// Gate: only projects that are in some MENTORING round (any status)
|
||||
projectRoundStates: {
|
||||
some: { round: { roundType: 'MENTORING' } },
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
@@ -718,6 +743,16 @@ export const mentorRouter = router({
|
||||
},
|
||||
})
|
||||
|
||||
if (projects.length === 0) {
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message:
|
||||
'None of the selected projects are in a mentoring round. Add them to a mentoring round first.',
|
||||
})
|
||||
}
|
||||
|
||||
const ineligibleCount = input.projectIds.length - projects.length
|
||||
|
||||
// Track per-mentor (for emails) and per-project (for team intros) state.
|
||||
const perMentor = new Map<
|
||||
string,
|
||||
@@ -884,6 +919,7 @@ export const mentorRouter = router({
|
||||
return {
|
||||
totalAssigned,
|
||||
totalSkipped,
|
||||
ineligibleProjectCount: ineligibleCount,
|
||||
touchedProjectCount: touchedProjectIds.size,
|
||||
perMentor: Array.from(perMentor.entries()).map(([id, b]) => ({
|
||||
mentorId: id,
|
||||
|
||||
Reference in New Issue
Block a user