diff --git a/src/app/(admin)/admin/projects/[id]/page.tsx b/src/app/(admin)/admin/projects/[id]/page.tsx index e8331c9..e56c742 100644 --- a/src/app/(admin)/admin/projects/[id]/page.tsx +++ b/src/app/(admin)/admin/projects/[id]/page.tsx @@ -927,7 +927,7 @@ function EvaluationDetailSheet({ if (type === 'section_header') return null - if (type === 'boolean') { + if (type === 'boolean' || type === 'advance') { return (
{label} diff --git a/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx b/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx index 52959f5..bb2a502 100644 --- a/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx +++ b/src/app/(jury)/jury/competitions/[roundId]/projects/[projectId]/evaluate/page.tsx @@ -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 ( +
+
+ + {criterion.description && ( +

{criterion.description}

+ )} +
+
+ + +
+
+ ) + } + if (criterion.type === 'boolean') { const currentValue = criteriaValues[criterion.id] return ( diff --git a/src/components/forms/evaluation-form.tsx b/src/components/forms/evaluation-form.tsx index d789c68..ba9fcd6 100644 --- a/src/components/forms/evaluation-form.tsx +++ b/src/components/forms/evaluation-form.tsx @@ -42,7 +42,7 @@ import { toast } from 'sonner' import { CountdownTimer } from '@/components/shared/countdown-timer' // Define criterion type from the evaluation form JSON -type CriterionType = 'numeric' | 'text' | 'boolean' | 'section_header' +type CriterionType = 'numeric' | 'text' | 'boolean' | 'advance' | 'section_header' interface CriterionCondition { criterionId: string @@ -96,7 +96,7 @@ const createEvaluationSchema = (criteria: Criterion[]) => { criterionFields[c.id] = z.number() } else if (type === 'text') { criterionFields[c.id] = z.string() - } else if (type === 'boolean') { + } else if (type === 'boolean' || type === 'advance') { criterionFields[c.id] = z.boolean() } } @@ -180,7 +180,7 @@ export function EvaluationForm({ defaultCriterionScores[c.id] = typeof existing === 'number' ? existing : Math.ceil((c.scale ?? 5) / 2) } else if (type === 'text') { defaultCriterionScores[c.id] = typeof existing === 'string' ? existing : '' - } else if (type === 'boolean') { + } else if (type === 'boolean' || type === 'advance') { defaultCriterionScores[c.id] = typeof existing === 'boolean' ? existing : false } }) @@ -225,7 +225,7 @@ export function EvaluationForm({ } else if (type === 'text') { const val = watchedScores?.[c.id] if (typeof val === 'string' && val.length > 0) criteriaDone++ - } else if (type === 'boolean') { + } else if (type === 'boolean' || type === 'advance') { if (touchedCriteria.has(c.id)) criteriaDone++ } } @@ -470,6 +470,19 @@ export function EvaluationForm({ ) } + // Advance (prominent boolean-valued criterion) + if (type === 'advance') { + return ( + + ) + } + return null })} @@ -947,6 +960,88 @@ function BooleanCriterionField({ ) } +// Advance criterion field component (prominent boolean — "should this project advance?") +function AdvanceCriterionField({ + criterion, + control, + disabled, + onTouch, +}: { + criterion: Criterion + control: any + disabled: boolean + onTouch: (criterionId: string) => void +}) { + const trueLabel = criterion.trueLabel || 'Yes' + const falseLabel = criterion.falseLabel || 'No' + + return ( + ( +
+
+
+ + {criterion.required && ( + Required + )} +
+ {criterion.description && ( +

+ {criterion.description} +

+ )} +
+
+ + +
+
+ )} + /> + ) +} + // Progress indicator component function ProgressIndicator({ percentage, diff --git a/src/components/observer/observer-project-detail.tsx b/src/components/observer/observer-project-detail.tsx index 0b3e03d..c5f721d 100644 --- a/src/components/observer/observer-project-detail.tsx +++ b/src/components/observer/observer-project-detail.tsx @@ -737,7 +737,7 @@ export function ObserverProjectDetail({ projectId }: { projectId: string }) { if (type === 'section_header') return null - if (type === 'boolean') { + if (type === 'boolean' || type === 'advance') { return (