Files
MOPC-Portal/src/components/admin/pipeline/sections/assignment-section.tsx

149 lines
5.0 KiB
TypeScript
Raw Normal View History

'use client'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { InfoTooltip } from '@/components/ui/info-tooltip'
import type { EvaluationConfig } from '@/types/pipeline-wizard'
type AssignmentSectionProps = {
config: EvaluationConfig
onChange: (config: EvaluationConfig) => void
isActive?: boolean
}
export function AssignmentSection({ config, onChange, isActive }: AssignmentSectionProps) {
const updateConfig = (updates: Partial<EvaluationConfig>) => {
onChange({ ...config, ...updates })
}
return (
<div className="space-y-6">
<div className="grid gap-4 sm:grid-cols-3">
<div className="space-y-2">
<div className="flex items-center gap-1.5">
<Label>Required Reviews per Project</Label>
<InfoTooltip content="Number of independent jury evaluations needed per project before it can be decided." />
</div>
<Input
type="number"
min={1}
max={20}
value={config.requiredReviews ?? 3}
disabled={isActive}
onChange={(e) =>
updateConfig({ requiredReviews: parseInt(e.target.value) || 3 })
}
/>
<p className="text-xs text-muted-foreground">
Minimum number of jury evaluations per project
</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-1.5">
<Label>Max Load per Juror</Label>
<InfoTooltip content="Maximum number of projects a single juror can be assigned in this stage." />
</div>
<Input
type="number"
min={1}
max={100}
value={config.maxLoadPerJuror ?? 20}
disabled={isActive}
onChange={(e) =>
updateConfig({ maxLoadPerJuror: parseInt(e.target.value) || 20 })
}
/>
<p className="text-xs text-muted-foreground">
Maximum projects assigned to one juror
</p>
</div>
<div className="space-y-2">
<div className="flex items-center gap-1.5">
<Label>Min Load per Juror</Label>
<InfoTooltip content="Minimum target assignments per juror. The system prioritizes jurors below this threshold." />
</div>
<Input
type="number"
min={0}
max={50}
value={config.minLoadPerJuror ?? 5}
disabled={isActive}
onChange={(e) =>
updateConfig({ minLoadPerJuror: parseInt(e.target.value) || 5 })
}
/>
<p className="text-xs text-muted-foreground">
Target minimum projects per juror
</p>
</div>
</div>
{(config.minLoadPerJuror ?? 0) > (config.maxLoadPerJuror ?? 20) && (
<p className="text-sm text-destructive">
Min load per juror cannot exceed max load per juror.
</p>
)}
<div className="flex items-center justify-between">
<div>
<div className="flex items-center gap-1.5">
<Label>Availability Weighting</Label>
<InfoTooltip content="When enabled, jurors who are available during the voting window are prioritized in assignment." />
</div>
<p className="text-xs text-muted-foreground">
Factor in juror availability when assigning projects
</p>
</div>
<Switch
checked={config.availabilityWeighting ?? true}
onCheckedChange={(checked) =>
updateConfig({ availabilityWeighting: checked })
}
disabled={isActive}
/>
</div>
<div className="space-y-2">
<div className="flex items-center gap-1.5">
<Label>Overflow Policy</Label>
<InfoTooltip content="'Queue' holds excess projects, 'Expand Pool' invites more jurors, 'Reduce Reviews' lowers the required review count." />
</div>
<Select
value={config.overflowPolicy ?? 'queue'}
onValueChange={(value) =>
updateConfig({
overflowPolicy: value as EvaluationConfig['overflowPolicy'],
})
}
disabled={isActive}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="queue">
Queue Hold unassigned projects for manual assignment
</SelectItem>
<SelectItem value="expand_pool">
Expand Pool Invite additional jurors automatically
</SelectItem>
<SelectItem value="reduce_reviews">
Reduce Reviews Lower required reviews to fit available jurors
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)
}