import { useRef, useEffect } from 'react' import { Play, Link2 } from 'lucide-react' import { DynamicArrayField } from './DynamicArrayField' import { useTreeEditorStore, collectAllNodesFlat } from '@/store/treeEditorStore' import type { TreeStructure, TreeOption } from '@/types' import { cn } from '@/lib/utils' import { InfoTip } from '@/components/common/InfoTip' interface NodeFormDecisionProps { node: TreeStructure onUpdate: (updates: Partial) => void } // Convert index to letter (0=A, 1=B, 2=C, etc.) const indexToLetter = (index: number): string => { return String.fromCharCode(65 + index) // 65 is ASCII for 'A' } export function NodeFormDecision({ node, onUpdate }: NodeFormDecisionProps) { const { validationErrors } = useTreeEditorStore() const isRootNode = node.id === 'root' // Track input elements by index so we can focus the newly added one const inputRefs = useRef>(new Map()) const shouldFocusLast = useRef(false) const questionError = validationErrors.find( e => e.nodeId === node.id && e.field === 'question' ) const optionsError = validationErrors.find( e => e.nodeId === node.id && e.field === 'options' ) // After options array grows (due to keyboard-triggered add), focus the last input useEffect(() => { if (shouldFocusLast.current) { shouldFocusLast.current = false const lastIndex = (node.options?.length ?? 1) - 1 inputRefs.current.get(lastIndex)?.focus() } }, [node.options?.length]) const handleAddOption = () => { const newOption: TreeOption = { id: crypto.randomUUID(), label: '', next_node_id: '' } onUpdate({ options: [...(node.options || []), newOption] }) } // Add a new option and focus it (used by keyboard shortcut) const handleAddOptionAndFocus = () => { shouldFocusLast.current = true handleAddOption() } const handleRemoveOption = (index: number) => { const newOptions = [...(node.options || [])] newOptions.splice(index, 1) onUpdate({ options: newOptions }) } const handleUpdateOption = (index: number, updates: Partial) => { const newOptions = [...(node.options || [])] newOptions[index] = { ...newOptions[index], ...updates } onUpdate({ options: newOptions }) } const handleReorderOptions = (fromIndex: number, toIndex: number) => { // Mutate local draft via onUpdate (backward-compatible: modal path relays to store, // canvas path updates local draft without writing to store early) const newOptions = [...(node.options || [])] const [moved] = newOptions.splice(fromIndex, 1) newOptions.splice(toIndex, 0, moved) onUpdate({ options: newOptions }) } return (
{/* Root node banner */} {isRootNode && (
Starting Question
)} {/* Question */}
onUpdate({ question: e.target.value })} placeholder={isRootNode ? "e.g., What type of issue are you experiencing?" : "e.g., Can you ping the server?"} className={cn( 'mt-1 block w-full rounded-md border px-3 py-2 text-sm', 'bg-card text-foreground placeholder:text-muted-foreground', 'focus:border-primary focus:outline-hidden focus:ring-1 focus:ring-primary/20', questionError ? 'border-red-400' : 'border-border' )} /> {questionError && (

{questionError.message}

)}
{/* Help Text */}