'use client' import { use, useState } from 'react' import Link from 'next/link' import type { Route } from 'next' import { useRouter } from 'next/navigation' import { trpc } from '@/lib/trpc/client' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Textarea } from '@/components/ui/textarea' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { toast } from 'sonner' import { cn } from '@/lib/utils' import { ArrowLeft, Plus, Loader2, Trash2, Users, Settings, Search, } from 'lucide-react' const capModeLabels = { HARD: 'Hard Cap', SOFT: 'Soft Cap', NONE: 'No Cap', } const capModeColors = { HARD: 'bg-red-100 text-red-700', SOFT: 'bg-amber-100 text-amber-700', NONE: 'bg-gray-100 text-gray-600', } type JuryGroupDetailPageProps = { params: Promise<{ groupId: string }> } export default function JuryGroupDetailPage({ params }: JuryGroupDetailPageProps) { const resolvedParams = use(params) const groupId = resolvedParams.groupId const router = useRouter() const utils = trpc.useUtils() const [addMemberDialogOpen, setAddMemberDialogOpen] = useState(false) const [userSearch, setUserSearch] = useState('') const [selectedUserId, setSelectedUserId] = useState('') const [selectedRole, setSelectedRole] = useState<'CHAIR' | 'MEMBER' | 'OBSERVER'>('MEMBER') const [maxAssignmentsOverride, setMaxAssignmentsOverride] = useState('') const { data: group, isLoading: loadingGroup } = trpc.juryGroup.getById.useQuery( { id: groupId }, { enabled: !!groupId } ) const { data: competition, isLoading: loadingCompetition } = trpc.competition.getById.useQuery( { id: group?.competitionId ?? '' }, { enabled: !!group?.competitionId } ) const { data: userSearchResults, isLoading: loadingUsers } = trpc.user.list.useQuery( { role: 'JURY_MEMBER', search: userSearch, page: 1, perPage: 20, }, { enabled: addMemberDialogOpen } ) const { data: selfServiceData } = trpc.juryGroup.reviewSelfServiceValues.useQuery( { juryGroupId: groupId }, { enabled: !!groupId } ) const addMemberMutation = trpc.juryGroup.addMember.useMutation({ onSuccess: () => { utils.juryGroup.getById.invalidate({ id: groupId }) utils.juryGroup.reviewSelfServiceValues.invalidate({ juryGroupId: groupId }) toast.success('Member added') setAddMemberDialogOpen(false) setSelectedUserId('') setUserSearch('') setMaxAssignmentsOverride('') }, onError: (err) => toast.error(err.message), }) const removeMemberMutation = trpc.juryGroup.removeMember.useMutation({ onSuccess: () => { utils.juryGroup.getById.invalidate({ id: groupId }) utils.juryGroup.reviewSelfServiceValues.invalidate({ juryGroupId: groupId }) toast.success('Member removed') }, onError: (err) => toast.error(err.message), }) const updateMemberMutation = trpc.juryGroup.updateMember.useMutation({ onSuccess: () => { utils.juryGroup.getById.invalidate({ id: groupId }) toast.success('Member updated') }, onError: (err) => toast.error(err.message), }) const updateGroupMutation = trpc.juryGroup.update.useMutation({ onSuccess: () => { utils.juryGroup.getById.invalidate({ id: groupId }) utils.juryGroup.list.invalidate() toast.success('Jury group updated') }, onError: (err) => toast.error(err.message), }) const handleAddMember = () => { if (!selectedUserId) { toast.error('Please select a user') return } addMemberMutation.mutate({ juryGroupId: groupId, userId: selectedUserId, role: selectedRole, maxAssignmentsOverride: maxAssignmentsOverride ? parseInt(maxAssignmentsOverride, 10) : null, }) } const handleRemoveMember = (memberId: string) => { if (!confirm('Remove this member from the jury group?')) return removeMemberMutation.mutate({ id: memberId }) } const handleRoleChange = (memberId: string, role: 'CHAIR' | 'MEMBER' | 'OBSERVER') => { updateMemberMutation.mutate({ id: memberId, role }) } if (loadingGroup || loadingCompetition) { return (
The requested jury group could not be found.
{competition?.name ?? 'Loading...'}
No members yet. Add jury members to this group.
) : (