feat(assignments): reshuffle dropped juror projects within caps
Some checks failed
Build and Push Docker Image / build (push) Failing after 3m38s

This commit is contained in:
Claw
2026-02-19 23:12:55 +01:00
parent 9d945c33f9
commit d3a63b0354
2 changed files with 290 additions and 0 deletions

View File

@@ -2358,6 +2358,7 @@ function RoundUnassignedQueue({ roundId, requiredReviews = 3 }: { roundId: strin
// ── Jury Progress Table ──────────────────────────────────────────────────
function JuryProgressTable({ roundId }: { roundId: string }) {
const utils = trpc.useUtils()
const { data: workload, isLoading } = trpc.analytics.getJurorWorkload.useQuery(
{ roundId },
{ refetchInterval: 15_000 },
@@ -2370,6 +2371,21 @@ function JuryProgressTable({ roundId }: { roundId: string }) {
onError: (err) => toast.error(err.message),
})
const reshuffleMutation = trpc.assignment.reassignDroppedJuror.useMutation({
onSuccess: (data) => {
utils.assignment.listByStage.invalidate({ roundId })
utils.roundEngine.getProjectStates.invalidate({ roundId })
utils.analytics.getJurorWorkload.invalidate({ roundId })
if (data.failedCount > 0) {
toast.warning(`Reassigned ${data.movedCount} project(s). ${data.failedCount} could not be reassigned (all remaining jurors at cap/blocked).`)
} else {
toast.success(`Reassigned ${data.movedCount} project(s) evenly across available jurors.`)
}
},
onError: (err) => toast.error(err.message),
})
return (
<Card>
<CardHeader>
@@ -2425,6 +2441,33 @@ function JuryProgressTable({ roundId }: { roundId: string }) {
<TooltipContent side="left"><p>Notify this juror of their assignments</p></TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider delayDuration={200}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-5 w-5 text-muted-foreground hover:text-destructive"
disabled={reshuffleMutation.isPending}
onClick={() => {
const ok = window.confirm(
`Reassign all pending/draft projects from ${juror.name} to other jurors within their caps? This cannot be undone.`
)
if (!ok) return
reshuffleMutation.mutate({ roundId, jurorId: juror.id })
}}
>
{reshuffleMutation.isPending && reshuffleMutation.variables?.jurorId === juror.id ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : (
<UserPlus className="h-3 w-3" />
)}
</Button>
</TooltipTrigger>
<TooltipContent side="left"><p>Drop juror + reshuffle pending projects</p></TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
<div className="h-2 bg-muted rounded-full overflow-hidden">