feat: render advance criterion on juror evaluation page and fix related renderers
- Jury evaluate page: add prominent advance criterion block (h-14, brand-blue border) before boolean block, fix type cast to include 'advance', add advance to required-field validation - evaluation-form.tsx: add 'advance' to CriterionType, schema, default values, progress tracking, rendering via new AdvanceCriterionField component with prominent styling - Admin project detail: treat advance same as boolean in EvaluationDetailSheet criterion score display - Observer project detail: treat advance same as boolean in evaluation criterion score display Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -927,7 +927,7 @@ function EvaluationDetailSheet({
|
||||
|
||||
if (type === 'section_header') return null
|
||||
|
||||
if (type === 'boolean') {
|
||||
if (type === 'boolean' || type === 'advance') {
|
||||
return (
|
||||
<div key={key} className="flex items-center justify-between p-2.5 rounded-lg border">
|
||||
<span className="text-sm">{label}</span>
|
||||
|
||||
@@ -164,7 +164,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
|
||||
id: c.id,
|
||||
label: c.label,
|
||||
description: c.description,
|
||||
type: type as 'numeric' | 'text' | 'boolean' | 'section_header',
|
||||
type: type as 'numeric' | 'text' | 'boolean' | 'advance' | 'section_header',
|
||||
weight: c.weight,
|
||||
minScore,
|
||||
maxScore,
|
||||
@@ -352,7 +352,7 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
|
||||
setIsSubmitting(false)
|
||||
return
|
||||
}
|
||||
if (c.type === 'boolean' && val === undefined) {
|
||||
if ((c.type === 'boolean' || c.type === 'advance') && val === undefined) {
|
||||
toast.error(`Please answer "${c.label}"`)
|
||||
isSubmittingRef.current = false
|
||||
setIsSubmitting(false)
|
||||
@@ -657,6 +657,51 @@ export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
|
||||
)
|
||||
}
|
||||
|
||||
if (criterion.type === 'advance') {
|
||||
const currentValue = criteriaValues[criterion.id]
|
||||
return (
|
||||
<div key={criterion.id} className="space-y-3 p-5 border-2 border-brand-blue/30 rounded-xl bg-brand-blue/5">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-base font-semibold text-brand-blue">
|
||||
{criterion.label}
|
||||
<span className="text-destructive ml-1">*</span>
|
||||
</Label>
|
||||
{criterion.description && (
|
||||
<p className="text-sm text-muted-foreground">{criterion.description}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleCriterionChange(criterion.id, true)}
|
||||
className={cn(
|
||||
'flex-1 h-14 rounded-xl border-2 flex items-center justify-center text-base font-semibold transition-all',
|
||||
currentValue === true
|
||||
? 'border-emerald-500 bg-emerald-50 text-emerald-700 shadow-sm ring-2 ring-emerald-200'
|
||||
: 'border-border hover:border-emerald-300 hover:bg-emerald-50/50'
|
||||
)}
|
||||
>
|
||||
<ThumbsUp className="mr-2 h-5 w-5" />
|
||||
{criterion.trueLabel || 'Yes'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleCriterionChange(criterion.id, false)}
|
||||
className={cn(
|
||||
'flex-1 h-14 rounded-xl border-2 flex items-center justify-center text-base font-semibold transition-all',
|
||||
currentValue === false
|
||||
? 'border-red-500 bg-red-50 text-red-700 shadow-sm ring-2 ring-red-200'
|
||||
: 'border-border hover:border-red-300 hover:bg-red-50/50'
|
||||
)}
|
||||
>
|
||||
<ThumbsDown className="mr-2 h-5 w-5" />
|
||||
{criterion.falseLabel || 'No'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (criterion.type === 'boolean') {
|
||||
const currentValue = criteriaValues[criterion.id]
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user