feat(admin): multi-mentor stacking UI + change-request inbox (PR8 Task 8)
- /admin/projects/[id]/mentor renders all co-mentors as a list with per-row
Unassign (confirm dialog) and a stacking "Add a mentor" flow that no longer
hides when at least one mentor is assigned. Candidates and AI suggestions
filter out already-assigned mentors.
- Pending change-requests panel appears above the mentor list when there are
open requests for the project, with per-card Mark Resolved / Dismiss actions
routed through mentor.resolveChangeRequest (optional resolution note).
- MentoringRoundOverview gains a "Pending change requests" row showing the
PENDING count across the program; the Review link deep-links to the first
pending request's project mentor page.
- mentor.unassign now accepts { assignmentId } so the admin UI can target a
specific co-mentor (legacy { projectId }-only callers still work and remove
the most-recent assignment).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -565,27 +565,45 @@ export const mentorRouter = router({
|
||||
}),
|
||||
|
||||
/**
|
||||
* Remove mentor assignment
|
||||
* Remove mentor assignment.
|
||||
*
|
||||
* Multi-mentor (PR8): callers should pass `assignmentId` to target a
|
||||
* specific co-mentor. Legacy callers passing only `projectId` get the
|
||||
* most-recent assignment removed (kept for backward compatibility).
|
||||
*/
|
||||
unassign: adminProcedure
|
||||
.input(z.object({ projectId: z.string() }))
|
||||
.input(
|
||||
z
|
||||
.object({
|
||||
assignmentId: z.string().optional(),
|
||||
projectId: z.string().optional(),
|
||||
})
|
||||
.refine((v) => !!v.assignmentId || !!v.projectId, {
|
||||
message: 'Either assignmentId or projectId is required',
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
// TODO(PR8 Task 8): admin UI should specify which mentor to drop when
|
||||
// multiple are assigned. Legacy callers pass only projectId — we resolve
|
||||
// to the most-recent assignment for backward compatibility.
|
||||
const assignment = await ctx.prisma.mentorAssignment.findFirst({
|
||||
where: { projectId: input.projectId },
|
||||
orderBy: { assignedAt: 'desc' },
|
||||
include: {
|
||||
mentor: { select: { id: true, name: true } },
|
||||
project: { select: { id: true, title: true } },
|
||||
},
|
||||
})
|
||||
const assignment = input.assignmentId
|
||||
? await ctx.prisma.mentorAssignment.findUnique({
|
||||
where: { id: input.assignmentId },
|
||||
include: {
|
||||
mentor: { select: { id: true, name: true } },
|
||||
project: { select: { id: true, title: true } },
|
||||
},
|
||||
})
|
||||
: await ctx.prisma.mentorAssignment.findFirst({
|
||||
where: { projectId: input.projectId! },
|
||||
orderBy: { assignedAt: 'desc' },
|
||||
include: {
|
||||
mentor: { select: { id: true, name: true } },
|
||||
project: { select: { id: true, title: true } },
|
||||
},
|
||||
})
|
||||
|
||||
if (!assignment) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: 'No mentor assignment found for this project',
|
||||
message: 'No mentor assignment found',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -602,7 +620,7 @@ export const mentorRouter = router({
|
||||
entityType: 'MentorAssignment',
|
||||
entityId: assignment.id,
|
||||
detailsJson: {
|
||||
projectId: input.projectId,
|
||||
projectId: assignment.project.id,
|
||||
projectTitle: assignment.project.title,
|
||||
mentorId: assignment.mentor.id,
|
||||
mentorName: assignment.mentor.name,
|
||||
|
||||
Reference in New Issue
Block a user