Fix evaluation criteria, jury preferences, assignment config, and dashboard stats
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m5s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m5s
- Fix criteria not showing for jurors: fetch active form independently via
getStageForm query instead of relying on existing evaluation record
- Fix scoringMode default from 'global' to 'criteria' (matching schema)
- Parse scale string format ("1-10") into minScore/maxScore for criteria display
- Fix COI dialog dismissal: prevent outside click on evaluate page Dialog
- Fix requiredReviews hardcoded to 3: read from round configJson in 4 locations
- Add jury preferences banner for unconfirmed caps on jury dashboard
- Add updateJuryPreferences tRPC procedure for self-service cap/ratio
- Simplify onboarding: always show jury step, allow cap up to 50
- Add role/ratio/availability fields to jury member invite dialog
- Simplify jury group settings (keep only defaultMaxAssignments)
- Enforce deliberation showCollectiveRankings flag for non-admin users
- Redesign dashboard stat cards: editorial data strip on mobile,
clean grid layout on desktop (no more generic card pattern)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,10 +51,9 @@ type JuryPref = {
|
||||
juryGroupMemberId: string
|
||||
juryGroupName: string
|
||||
currentCap: number
|
||||
allowCapAdjustment: boolean
|
||||
allowRatioAdjustment: boolean
|
||||
selfServiceCap: number | null
|
||||
selfServiceRatio: number | null
|
||||
preferredStartupRatio: number | null
|
||||
}
|
||||
|
||||
export default function OnboardingPage() {
|
||||
@@ -530,60 +529,59 @@ export default function OnboardingPage() {
|
||||
{juryMemberships.map((m) => {
|
||||
const pref = juryPrefs.get(m.juryGroupMemberId) ?? {}
|
||||
const capValue = pref.cap ?? m.selfServiceCap ?? m.currentCap
|
||||
const ratioValue = pref.ratio ?? m.selfServiceRatio ?? 0.5
|
||||
const ratioValue = pref.ratio ?? m.selfServiceRatio ?? m.preferredStartupRatio ?? 0.5
|
||||
|
||||
return (
|
||||
<div key={m.juryGroupMemberId} className="rounded-lg border p-4 space-y-4">
|
||||
<h4 className="font-medium text-sm">{m.juryGroupName}</h4>
|
||||
|
||||
{m.allowCapAdjustment && (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Maximum assignments: {capValue}
|
||||
</Label>
|
||||
<Slider
|
||||
value={[capValue]}
|
||||
onValueChange={([v]) =>
|
||||
setJuryPrefs((prev) => {
|
||||
const next = new Map(prev)
|
||||
next.set(m.juryGroupMemberId, { ...pref, cap: v })
|
||||
return next
|
||||
})
|
||||
}
|
||||
min={1}
|
||||
max={m.currentCap}
|
||||
step={1}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Admin default: {m.currentCap}. You may reduce this to match your availability.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Maximum assignments: {capValue}
|
||||
</Label>
|
||||
<Slider
|
||||
value={[capValue]}
|
||||
onValueChange={([v]) =>
|
||||
setJuryPrefs((prev) => {
|
||||
const next = new Map(prev)
|
||||
next.set(m.juryGroupMemberId, { ...pref, cap: v })
|
||||
return next
|
||||
})
|
||||
}
|
||||
min={1}
|
||||
max={50}
|
||||
step={1}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Admin suggestion: {m.currentCap}. Adjust to match your availability.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{m.allowRatioAdjustment && (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Startup vs Business Concept ratio: {Math.round(ratioValue * 100)}% / {Math.round((1 - ratioValue) * 100)}%
|
||||
</Label>
|
||||
<Slider
|
||||
value={[ratioValue * 100]}
|
||||
onValueChange={([v]) =>
|
||||
setJuryPrefs((prev) => {
|
||||
const next = new Map(prev)
|
||||
next.set(m.juryGroupMemberId, { ...pref, ratio: v / 100 })
|
||||
return next
|
||||
})
|
||||
}
|
||||
min={0}
|
||||
max={100}
|
||||
step={5}
|
||||
/>
|
||||
<div className="flex justify-between text-xs text-muted-foreground">
|
||||
<span>More Business Concepts</span>
|
||||
<span>More Startups</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Category preference: {Math.round(ratioValue * 100)}% Startups / {Math.round((1 - ratioValue) * 100)}% Business Concepts
|
||||
</Label>
|
||||
<Slider
|
||||
value={[ratioValue * 100]}
|
||||
onValueChange={([v]) =>
|
||||
setJuryPrefs((prev) => {
|
||||
const next = new Map(prev)
|
||||
next.set(m.juryGroupMemberId, { ...pref, ratio: v / 100 })
|
||||
return next
|
||||
})
|
||||
}
|
||||
min={0}
|
||||
max={100}
|
||||
step={10}
|
||||
/>
|
||||
<div className="flex justify-between text-xs text-muted-foreground">
|
||||
<span>More Business Concepts</span>
|
||||
<span>More Startups</span>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground/70 italic">
|
||||
This is a preference, not a guarantee. Due to the number of projects, the system will try to match your preference but exact ratios cannot be ensured.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user