'use client' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Slider } from '@/components/ui/slider' import { Textarea } from '@/components/ui/textarea' import { Label } from '@/components/ui/label' import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' import { cn } from '@/lib/utils' import { ThumbsUp, ThumbsDown, CheckCircle2 } from 'lucide-react' export type EvaluationCriterion = { id: string label: string description?: string | null type: 'numeric' | 'text' | 'boolean' | 'advance' | 'section_header' weight?: number | null minScore: number maxScore: number required: boolean trueLabel: string falseLabel: string maxLength: number placeholder: string } export type ScoringMode = 'criteria' | 'global' | 'binary' export type EvaluationFormFieldsProps = { criteria: EvaluationCriterion[] scoringMode: ScoringMode requireFeedback: boolean feedbackMinLength: number criteriaValues: Record globalScore: string binaryDecision: '' | 'accept' | 'reject' feedbackText: string isReadOnly: boolean lastSavedAt?: Date | null headerDescription?: string onCriterionChange: (key: string, value: number | boolean | string) => void onGlobalScoreChange: (value: string) => void onBinaryChange: (value: 'accept' | 'reject') => void onFeedbackChange: (value: string) => void } /** * Parse an EvaluationForm.criteriaJson payload into typed criteria for display. * Kept in this file so every consumer normalizes in the same way. */ export function parseCriteriaFromForm( criteriaJson: ReadonlyArray> | null | undefined, ): EvaluationCriterion[] { if (!criteriaJson) return [] return criteriaJson.map((raw) => { const c = raw as Record const type = (c.type as EvaluationCriterion['type']) || 'numeric' let minScore = 1 let maxScore = 10 if (type === 'numeric' && typeof c.scale === 'string') { const parts = c.scale.split('-').map(Number) if (parts.length === 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) { minScore = parts[0] maxScore = parts[1] } } return { id: c.id as string, label: c.label as string, description: (c.description as string | null | undefined) ?? null, type, weight: (c.weight as number | null | undefined) ?? null, minScore, maxScore, required: (c.required as boolean | undefined) ?? true, trueLabel: (c.trueLabel as string | undefined) || 'Yes', falseLabel: (c.falseLabel as string | undefined) || 'No', maxLength: (c.maxLength as number | undefined) || 1000, placeholder: (c.placeholder as string | undefined) || '', } }) } export function EvaluationFormFields({ criteria, scoringMode, requireFeedback, feedbackMinLength, criteriaValues, globalScore, binaryDecision, feedbackText, isReadOnly, lastSavedAt, headerDescription, onCriterionChange, onGlobalScoreChange, onBinaryChange, onFeedbackChange, }: EvaluationFormFieldsProps) { const description = headerDescription ?? (scoringMode === 'criteria' ? 'Complete all required fields below' : `Provide your assessment using the ${scoringMode} scoring method`) return (
Evaluation Form {description}
{lastSavedAt && ( Saved {lastSavedAt.toLocaleTimeString()} )}
{scoringMode === 'criteria' && criteria.length > 0 && (
{criteria.map((criterion) => { if (criterion.type === 'section_header') { return (

{criterion.label}

{criterion.description && (

{criterion.description}

)}
) } if (criterion.type === 'advance') { const currentValue = criteriaValues[criterion.id] return (
{criterion.description && (

{criterion.description}

)}
) } if (criterion.type === 'boolean') { const currentValue = criteriaValues[criterion.id] return (
{criterion.description && (

{criterion.description}

)}
) } if (criterion.type === 'text') { const currentValue = (criteriaValues[criterion.id] as string) || '' return (
{criterion.description && (

{criterion.description}

)}