From 3a076efaf6eb26ccbb1221976f6d809d34589925 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 01:15:58 +0000 Subject: [PATCH] Refactor component tree builder state --- src/components/ComponentTreeBuilder.tsx | 91 +++--------------- src/hooks/use-component-tree-builder.ts | 118 ++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 76 deletions(-) create mode 100644 src/hooks/use-component-tree-builder.ts diff --git a/src/components/ComponentTreeBuilder.tsx b/src/components/ComponentTreeBuilder.tsx index 347da3c..9b5ed34 100644 --- a/src/components/ComponentTreeBuilder.tsx +++ b/src/components/ComponentTreeBuilder.tsx @@ -1,94 +1,33 @@ -import { useState } from 'react' import { ComponentNode } from '@/types/project' -import { AIService } from '@/lib/ai-service' -import { toast } from 'sonner' import componentTreeBuilderData from '@/data/component-tree-builder.json' import { ComponentInspector } from '@/components/component-tree-builder/ComponentInspector' import { ComponentTreeToolbar } from '@/components/component-tree-builder/ComponentTreeToolbar' import { ComponentTreeView } from '@/components/component-tree-builder/ComponentTreeView' -import { - addChildNode, - createComponentNode, - deleteNodeFromTree, - findNodeById, - updateNodeInTree, -} from '@/components/component-tree-builder/tree-utils' +import { useComponentTreeBuilder } from '@/hooks/use-component-tree-builder' interface ComponentTreeBuilderProps { components: ComponentNode[] onComponentsChange: (components: ComponentNode[]) => void } -const { muiComponents, prompts } = componentTreeBuilderData +const { muiComponents } = componentTreeBuilderData export function ComponentTreeBuilder({ components, onComponentsChange, }: ComponentTreeBuilderProps) { - const [selectedNodeId, setSelectedNodeId] = useState(null) - const [expandedNodes, setExpandedNodes] = useState>(new Set()) - - const selectedNode = selectedNodeId - ? findNodeById(components, selectedNodeId) - : null - - const addRootComponent = () => { - const newNode = createComponentNode({ - name: `Component${components.length + 1}`, - }) - onComponentsChange([...components, newNode]) - setSelectedNodeId(newNode.id) - } - - const addChildComponent = (parentId: string) => { - const newNode = createComponentNode() - onComponentsChange(addChildNode(components, parentId, newNode)) - setExpandedNodes(new Set([...expandedNodes, parentId])) - setSelectedNodeId(newNode.id) - } - - const deleteNode = (nodeId: string) => { - onComponentsChange(deleteNodeFromTree(components, nodeId)) - if (selectedNodeId === nodeId) { - setSelectedNodeId(null) - } - } - - const updateNode = (nodeId: string, updates: Partial) => { - onComponentsChange(updateNodeInTree(components, nodeId, updates)) - } - - const toggleExpand = (nodeId: string) => { - const newExpanded = new Set(expandedNodes) - if (newExpanded.has(nodeId)) { - newExpanded.delete(nodeId) - } else { - newExpanded.add(nodeId) - } - setExpandedNodes(newExpanded) - } - - const generateComponentWithAI = async () => { - const description = prompt(prompts.generateComponentDescription) - if (!description) return - - try { - toast.info('Generating component with AI...') - const component = await AIService.generateComponent(description) - - if (component) { - onComponentsChange([...components, component]) - setSelectedNodeId(component.id) - setExpandedNodes(new Set([...Array.from(expandedNodes), component.id])) - toast.success(`Component "${component.name}" created successfully!`) - } else { - toast.error('AI generation failed. Please try again.') - } - } catch (error) { - toast.error('Failed to generate component') - console.error(error) - } - } + const { + selectedNode, + selectedNodeId, + expandedNodes, + selectNode, + addRootComponent, + addChildComponent, + deleteNode, + updateNode, + toggleExpand, + generateComponentWithAI, + } = useComponentTreeBuilder({ components, onComponentsChange }) return (
@@ -101,7 +40,7 @@ export function ComponentTreeBuilder({ nodes={components} selectedNodeId={selectedNodeId} expandedNodes={expandedNodes} - onSelectNode={setSelectedNodeId} + onSelectNode={selectNode} onToggleExpand={toggleExpand} />
diff --git a/src/hooks/use-component-tree-builder.ts b/src/hooks/use-component-tree-builder.ts new file mode 100644 index 0000000..69ad5ce --- /dev/null +++ b/src/hooks/use-component-tree-builder.ts @@ -0,0 +1,118 @@ +import { useCallback, useMemo, useState } from 'react' +import { ComponentNode } from '@/types/project' +import { AIService } from '@/lib/ai-service' +import { toast } from 'sonner' +import componentTreeBuilderData from '@/data/component-tree-builder.json' +import { + addChildNode, + createComponentNode, + deleteNodeFromTree, + findNodeById, + updateNodeInTree, +} from '@/components/component-tree-builder/tree-utils' + +type ComponentTreeBuilderOptions = { + components: ComponentNode[] + onComponentsChange: (components: ComponentNode[]) => void +} + +const { prompts } = componentTreeBuilderData + +export function useComponentTreeBuilder({ + components, + onComponentsChange, +}: ComponentTreeBuilderOptions) { + const [selectedNodeId, setSelectedNodeId] = useState(null) + const [expandedNodes, setExpandedNodes] = useState>(new Set()) + + const selectedNode = useMemo( + () => (selectedNodeId ? findNodeById(components, selectedNodeId) : null), + [components, selectedNodeId] + ) + + const selectNode = useCallback((nodeId: string | null) => { + setSelectedNodeId(nodeId) + }, []) + + const addRootComponent = useCallback(() => { + const newNode = createComponentNode({ + name: `Component${components.length + 1}`, + }) + onComponentsChange([...components, newNode]) + setSelectedNodeId(newNode.id) + }, [components, onComponentsChange]) + + const addChildComponent = useCallback( + (parentId: string) => { + const newNode = createComponentNode() + onComponentsChange(addChildNode(components, parentId, newNode)) + setExpandedNodes(prevExpanded => new Set([...prevExpanded, parentId])) + setSelectedNodeId(newNode.id) + }, + [components, onComponentsChange] + ) + + const deleteNode = useCallback( + (nodeId: string) => { + onComponentsChange(deleteNodeFromTree(components, nodeId)) + if (selectedNodeId === nodeId) { + setSelectedNodeId(null) + } + }, + [components, onComponentsChange, selectedNodeId] + ) + + const updateNode = useCallback( + (nodeId: string, updates: Partial) => { + onComponentsChange(updateNodeInTree(components, nodeId, updates)) + }, + [components, onComponentsChange] + ) + + const toggleExpand = useCallback((nodeId: string) => { + setExpandedNodes(prevExpanded => { + const newExpanded = new Set(prevExpanded) + if (newExpanded.has(nodeId)) { + newExpanded.delete(nodeId) + } else { + newExpanded.add(nodeId) + } + return newExpanded + }) + }, []) + + const generateComponentWithAI = useCallback(async () => { + const description = prompt(prompts.generateComponentDescription) + if (!description) return + + try { + toast.info('Generating component with AI...') + const component = await AIService.generateComponent(description) + + if (component) { + onComponentsChange([...components, component]) + setSelectedNodeId(component.id) + setExpandedNodes(prevExpanded => new Set([...prevExpanded, component.id])) + toast.success(`Component "${component.name}" created successfully!`) + } else { + toast.error('AI generation failed. Please try again.') + } + } catch (error) { + toast.error('Failed to generate component') + console.error(error) + } + }, [components, onComponentsChange]) + + return { + selectedNode, + selectedNodeId, + expandedNodes, + selectNode, + addRootComponent, + addChildComponent, + deleteNode, + updateNode, + toggleExpand, + generateComponentWithAI, + } +}