diff --git a/src/app/(mentor)/mentor/projects/[id]/page.tsx b/src/app/(mentor)/mentor/projects/[id]/page.tsx index 2176d38..c347c5a 100644 --- a/src/app/(mentor)/mentor/projects/[id]/page.tsx +++ b/src/app/(mentor)/mentor/projects/[id]/page.tsx @@ -2,6 +2,7 @@ import { Suspense, use, useState, useEffect } from 'react' import { useRouter } from 'next/navigation' +import { useSession } from 'next-auth/react' import { trpc } from '@/lib/trpc/client' import { Card, @@ -31,6 +32,7 @@ import { AnimatedCard } from '@/components/shared/animated-container' import { FileViewer } from '@/components/shared/file-viewer' import { MentorChat } from '@/components/shared/mentor-chat' import { ProjectLogoWithUrl } from '@/components/shared/project-logo-with-url' +import { DropAssignmentDialog } from '@/components/mentor/drop-assignment-dialog' import { ArrowLeft, AlertCircle, @@ -76,6 +78,7 @@ const statusColors: Record m.role === 'LEAD') const otherMembers = project.teamMembers?.filter((m) => m.role !== 'LEAD') || [] - const mentorAssignmentId = project.mentorAssignment?.id + const mentorAssignment = project.mentorAssignment + const mentorAssignmentId = mentorAssignment?.id const programId = project.program?.id + const viewerIsAssignedMentor = + !!mentorAssignment && session?.user?.id === mentorAssignment.mentor?.id + const canDrop = + viewerIsAssignedMentor && + !mentorAssignment.droppedAt && + mentorAssignment.completionStatus !== 'completed' return (
@@ -179,6 +189,12 @@ function ProjectDetailContent({ projectId }: { projectId: string }) { )}
+ {canDrop && mentorAssignmentId && ( + + )} {project.assignedAt && ( diff --git a/src/components/mentor/drop-assignment-dialog.tsx b/src/components/mentor/drop-assignment-dialog.tsx new file mode 100644 index 0000000..d970fbe --- /dev/null +++ b/src/components/mentor/drop-assignment-dialog.tsx @@ -0,0 +1,111 @@ +'use client' + +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import { trpc } from '@/lib/trpc/client' +import { Button } from '@/components/ui/button' +import { Textarea } from '@/components/ui/textarea' +import { Label } from '@/components/ui/label' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog' +import { Loader2, UserMinus } from 'lucide-react' +import { toast } from 'sonner' + +const MIN_REASON = 10 +const MAX_REASON = 1000 + +export function DropAssignmentDialog({ + assignmentId, + projectTitle, +}: { + assignmentId: string + projectTitle: string +}) { + const router = useRouter() + const [open, setOpen] = useState(false) + const [reason, setReason] = useState('') + + const drop = trpc.mentor.dropAssignment.useMutation({ + onSuccess: () => { + toast.success('You have dropped this assignment.') + setOpen(false) + router.push('/mentor') + router.refresh() + }, + onError: (e) => { + toast.error(e.message) + }, + }) + + const trimmed = reason.trim() + const tooShort = trimmed.length < MIN_REASON + const tooLong = trimmed.length > MAX_REASON + + return ( + { + if (!drop.isPending) setOpen(next) + if (!next) setReason('') + }} + > + + + + + + Drop {projectTitle}? + + The team will be unassigned from you and an admin will be notified so they can find a + replacement mentor. Please share why so we can adjust future assignments. + + + +
+ +