Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
'use client'
|
|
|
|
|
|
|
|
|
|
import { useState } from 'react'
|
|
|
|
|
import { Trash2, UserPlus } from 'lucide-react'
|
|
|
|
|
import { toast } from 'sonner'
|
|
|
|
|
import { trpc } from '@/lib/trpc/client'
|
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
|
|
|
import {
|
|
|
|
|
Table,
|
|
|
|
|
TableBody,
|
|
|
|
|
TableCell,
|
|
|
|
|
TableHead,
|
|
|
|
|
TableHeader,
|
|
|
|
|
TableRow,
|
|
|
|
|
} from '@/components/ui/table'
|
|
|
|
|
import { Badge } from '@/components/ui/badge'
|
|
|
|
|
import {
|
|
|
|
|
AlertDialog,
|
|
|
|
|
AlertDialogAction,
|
|
|
|
|
AlertDialogCancel,
|
|
|
|
|
AlertDialogContent,
|
|
|
|
|
AlertDialogDescription,
|
|
|
|
|
AlertDialogFooter,
|
|
|
|
|
AlertDialogHeader,
|
|
|
|
|
AlertDialogTitle,
|
|
|
|
|
} from '@/components/ui/alert-dialog'
|
|
|
|
|
import { AddMemberDialog } from './add-member-dialog'
|
|
|
|
|
|
|
|
|
|
interface JuryMember {
|
|
|
|
|
id: string
|
|
|
|
|
userId: string
|
2026-02-16 12:46:01 +01:00
|
|
|
role?: string
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
user: {
|
|
|
|
|
id: string
|
|
|
|
|
name: string | null
|
|
|
|
|
email: string
|
|
|
|
|
}
|
2026-02-16 12:46:01 +01:00
|
|
|
maxAssignmentsOverride?: number | null
|
|
|
|
|
capModeOverride?: string | null
|
|
|
|
|
preferredStartupRatio?: number | null
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface JuryMembersTableProps {
|
|
|
|
|
juryGroupId: string
|
|
|
|
|
members: JuryMember[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function JuryMembersTable({ juryGroupId, members }: JuryMembersTableProps) {
|
|
|
|
|
const [addDialogOpen, setAddDialogOpen] = useState(false)
|
|
|
|
|
const [removingMemberId, setRemovingMemberId] = useState<string | null>(null)
|
|
|
|
|
const utils = trpc.useUtils()
|
|
|
|
|
|
|
|
|
|
const { mutate: removeMember, isPending: isRemoving } = trpc.juryGroup.removeMember.useMutation({
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
utils.juryGroup.getById.invalidate({ id: juryGroupId })
|
|
|
|
|
toast.success('Member removed successfully')
|
|
|
|
|
setRemovingMemberId(null)
|
|
|
|
|
},
|
|
|
|
|
onError: (err) => {
|
|
|
|
|
toast.error(err.message)
|
|
|
|
|
setRemovingMemberId(null)
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const handleRemove = (memberId: string) => {
|
|
|
|
|
removeMember({ id: memberId })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
<div className="flex justify-end">
|
|
|
|
|
<Button onClick={() => setAddDialogOpen(true)}>
|
|
|
|
|
<UserPlus className="mr-2 h-4 w-4" />
|
|
|
|
|
Add Member
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="rounded-md border">
|
|
|
|
|
<Table>
|
|
|
|
|
<TableHeader>
|
|
|
|
|
<TableRow>
|
|
|
|
|
<TableHead>Name</TableHead>
|
|
|
|
|
<TableHead>Email</TableHead>
|
|
|
|
|
<TableHead className="hidden sm:table-cell">Max Assignments</TableHead>
|
AI category-aware evaluation: per-round config, file parsing, shortlist, advance flow
- Per-juror cap mode (HARD/SOFT/NONE) in add-member dialog and members table
- Jury invite flow: create user + add to group + send invitation from dialog
- Per-round config: notifyOnAdvance, aiParseFiles, startupAdvanceCount, conceptAdvanceCount
- Moved notify-on-advance from competition-level to per-round setting
- AI filtering: round-tagged files with newest-first sorting, optional file content extraction
- File content extractor service (pdf-parse for PDF, utf-8 for text files)
- AI shortlist runs independently per category (STARTUP / BUSINESS_CONCEPT)
- generateAIRecommendations tRPC endpoint with per-round config integration
- AI recommendations UI: trigger button, confirmation dialog, per-category results display
- Category-aware advance dialog: select/deselect projects by category with target caps
- STAGE_ACTIVE bug fix in assignment router
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 10:09:52 +01:00
|
|
|
<TableHead className="hidden lg:table-cell">Cap Mode</TableHead>
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
<TableHead>Actions</TableHead>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHeader>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{members.length === 0 ? (
|
|
|
|
|
<TableRow>
|
2026-02-16 12:46:01 +01:00
|
|
|
<TableCell colSpan={5} className="text-center text-muted-foreground">
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
No members yet. Add members to get started.
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
) : (
|
|
|
|
|
members.map((member) => (
|
|
|
|
|
<TableRow key={member.id}>
|
|
|
|
|
<TableCell className="font-medium">
|
|
|
|
|
{member.user.name || 'Unnamed User'}
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell className="text-sm text-muted-foreground">
|
|
|
|
|
{member.user.email}
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell className="hidden sm:table-cell">
|
|
|
|
|
{member.maxAssignmentsOverride ?? '—'}
|
|
|
|
|
</TableCell>
|
AI category-aware evaluation: per-round config, file parsing, shortlist, advance flow
- Per-juror cap mode (HARD/SOFT/NONE) in add-member dialog and members table
- Jury invite flow: create user + add to group + send invitation from dialog
- Per-round config: notifyOnAdvance, aiParseFiles, startupAdvanceCount, conceptAdvanceCount
- Moved notify-on-advance from competition-level to per-round setting
- AI filtering: round-tagged files with newest-first sorting, optional file content extraction
- File content extractor service (pdf-parse for PDF, utf-8 for text files)
- AI shortlist runs independently per category (STARTUP / BUSINESS_CONCEPT)
- generateAIRecommendations tRPC endpoint with per-round config integration
- AI recommendations UI: trigger button, confirmation dialog, per-category results display
- Category-aware advance dialog: select/deselect projects by category with target caps
- STAGE_ACTIVE bug fix in assignment router
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 10:09:52 +01:00
|
|
|
<TableCell className="hidden lg:table-cell">
|
|
|
|
|
{member.capModeOverride ? (
|
|
|
|
|
<Badge variant="outline" className="text-[10px]">
|
|
|
|
|
{member.capModeOverride}
|
|
|
|
|
</Badge>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="text-muted-foreground text-xs">Group default</span>
|
|
|
|
|
)}
|
|
|
|
|
</TableCell>
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
<TableCell>
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => setRemovingMemberId(member.id)}
|
|
|
|
|
disabled={isRemoving}
|
|
|
|
|
>
|
|
|
|
|
<Trash2 className="h-4 w-4 text-destructive" />
|
|
|
|
|
</Button>
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<AddMemberDialog
|
|
|
|
|
juryGroupId={juryGroupId}
|
|
|
|
|
open={addDialogOpen}
|
|
|
|
|
onOpenChange={setAddDialogOpen}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<AlertDialog open={!!removingMemberId} onOpenChange={() => setRemovingMemberId(null)}>
|
|
|
|
|
<AlertDialogContent>
|
|
|
|
|
<AlertDialogHeader>
|
|
|
|
|
<AlertDialogTitle>Remove Member</AlertDialogTitle>
|
|
|
|
|
<AlertDialogDescription>
|
|
|
|
|
Are you sure you want to remove this member from the jury group? This action cannot be undone.
|
|
|
|
|
</AlertDialogDescription>
|
|
|
|
|
</AlertDialogHeader>
|
|
|
|
|
<AlertDialogFooter>
|
|
|
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
|
|
|
<AlertDialogAction
|
|
|
|
|
onClick={() => removingMemberId && handleRemove(removingMemberId)}
|
|
|
|
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
|
|
|
>
|
|
|
|
|
Remove
|
|
|
|
|
</AlertDialogAction>
|
|
|
|
|
</AlertDialogFooter>
|
|
|
|
|
</AlertDialogContent>
|
|
|
|
|
</AlertDialog>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|