import { useState, useEffect, useCallback } from 'react' import { Modal } from '@/components/common/Modal' import { useTreeEditorStore } from '@/store/treeEditorStore' import { NodeFormDecision } from './NodeFormDecision' import { NodeFormAction } from './NodeFormAction' import { NodeFormResolution } from './NodeFormResolution' import type { TreeStructure } from '@/types' interface NodeEditorModalProps { node: TreeStructure onClose: () => void /** If true, this is a brand new node - cancel will delete it entirely */ isNewNode?: boolean } export function NodeEditorModal({ node, onClose, isNewNode = false }: NodeEditorModalProps) { const { updateNode, deleteNode, validationErrors } = useTreeEditorStore() const nodeErrors = validationErrors.filter(e => e.nodeId === node.id) // Local draft state - changes are NOT persisted until "Done" is clicked const [draft, setDraft] = useState(() => structuredClone(node)) // Reset draft when node changes (e.g., external update) useEffect(() => { setDraft(structuredClone(node)) }, [node.id]) // Only reset when switching to a different node const handleUpdate = useCallback((updates: Partial) => { setDraft(prev => ({ ...prev, ...updates })) }, []) const handleSave = () => { // Commit all draft changes to the store // IMPORTANT: Exclude 'children' from the update - children are managed separately // by addNode/deleteNode and we don't want to overwrite them with stale draft data const { children, ...draftWithoutChildren } = draft updateNode(node.id, draftWithoutChildren) onClose() } const handleCancel = () => { if (isNewNode) { // Delete the unsaved new node entirely deleteNode(node.id) } // Discard changes and close (draft is just thrown away) onClose() } const getTitle = () => { switch (node.type) { case 'decision': return 'Edit Decision Node' case 'action': return 'Edit Action Node' case 'solution': return 'Edit Solution Node' default: return 'Edit Node' } } const footerContent = (
) return ( {/* Node ID display */}
Node ID: {node.id}
{/* Validation errors */} {nodeErrors.length > 0 && (
{nodeErrors.map((error, i) => (
{error.message}
))}
)} {/* Type-specific form - uses draft state, not the original node */} {draft.type === 'decision' && ( )} {draft.type === 'action' && ( )} {draft.type === 'solution' && ( )}
) } export default NodeEditorModal