import { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Pencil, Send, Plus, Trash2 } from 'lucide-react'; import type { ScientistAction, EpisodeState } from '@/types'; import { cn } from '@/lib/utils'; interface ProtocolEditorProps { episode: EpisodeState; onSubmit: (action: ScientistAction) => void; disabled?: boolean; className?: string; } export default function ProtocolEditor({ episode, onSubmit, disabled, className, }: ProtocolEditorProps) { const [actionType, setActionType] = useState<'propose_protocol' | 'revise_protocol' | 'request_info' | 'accept'>('propose_protocol'); const [sampleSize, setSampleSize] = useState(3); const [technique, setTechnique] = useState(''); const [durationDays, setDurationDays] = useState(5); const [controls, setControls] = useState(['baseline']); const [equipment, setEquipment] = useState([]); const [reagents, setReagents] = useState([]); const [rationale, setRationale] = useState(''); const [questions, setQuestions] = useState([]); const [newControl, setNewControl] = useState(''); const [newQuestion, setNewQuestion] = useState(''); // Pre-fill from current protocol if exists useEffect(() => { if (episode.protocol) { setSampleSize(episode.protocol.sample_size); setTechnique(episode.protocol.technique); setDurationDays(episode.protocol.duration_days); setControls([...episode.protocol.controls]); setEquipment([...episode.protocol.required_equipment]); setReagents([...episode.protocol.required_reagents]); setActionType(episode.round > 0 ? 'revise_protocol' : 'propose_protocol'); } }, [episode.protocol, episode.round]); function handleSubmit() { if (actionType === 'accept') { onSubmit({ action_type: 'accept', sample_size: 0, controls: [], technique: '', duration_days: 0, required_equipment: [], required_reagents: [], questions: [], rationale: '', }); return; } if (actionType === 'request_info') { onSubmit({ action_type: 'request_info', sample_size: 0, controls: [], technique: '', duration_days: 0, required_equipment: [], required_reagents: [], questions: questions.filter(Boolean), rationale: '', }); return; } onSubmit({ action_type: actionType, sample_size: sampleSize, controls: controls.filter(Boolean), technique, duration_days: durationDays, required_equipment: equipment.filter(Boolean), required_reagents: reagents.filter(Boolean), questions: [], rationale, }); } const isProtocolAction = actionType === 'propose_protocol' || actionType === 'revise_protocol'; const canSubmit = actionType === 'accept' || (actionType === 'request_info' && questions.some(Boolean)) || (isProtocolAction && sampleSize > 0 && technique && rationale); return (
Protocol Editor Craft your action
{/* Action type selector */}
{(['propose_protocol', 'revise_protocol', 'request_info', 'accept'] as const).map((t) => ( ))}
{isProtocolAction && (
setSampleSize(parseInt(e.target.value) || 0)} className="w-full rounded border border-border bg-background px-2 py-1 text-xs" /> setDurationDays(parseInt(e.target.value) || 0)} className="w-full rounded border border-border bg-background px-2 py-1 text-xs" /> setTechnique(e.target.value)} placeholder="e.g. fine_tuning" className="w-full rounded border border-border bg-background px-2 py-1 text-xs" />
{/* Controls */}
{controls.map((c, i) => ( {c} ))}
setNewControl(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter' && newControl.trim()) { setControls([...controls, newControl.trim()]); setNewControl(''); } }} placeholder="Add control..." className="flex-1 rounded border border-border bg-background px-2 py-0.5 text-[10px]" />
{/* Equipment from available */}
{episode.lab_constraints.equipment_available.map((e) => ( ))}
{/* Reagents from available */}
{episode.lab_constraints.reagents_available.map((r) => ( ))}
{/* Rationale */}