diff --git a/src/components/molecules/DataSourceEditorDialog.tsx b/src/components/molecules/DataSourceEditorDialog.tsx index 38098d4..ceec274 100644 --- a/src/components/molecules/DataSourceEditorDialog.tsx +++ b/src/components/molecules/DataSourceEditorDialog.tsx @@ -8,6 +8,7 @@ import { StaticSourceFields } from '@/components/molecules/data-source-editor/St import { ComputedSourceFields } from '@/components/molecules/data-source-editor/ComputedSourceFields' import { useDataSourceEditor } from '@/hooks/data/use-data-source-editor' import dataSourceEditorCopy from '@/data/data-source-editor-dialog.json' +import { useDataSourceEditor } from '@/hooks/use-data-source-editor' interface DataSourceEditorDialogProps { open: boolean diff --git a/src/hooks/use-data-source-editor.ts b/src/hooks/use-data-source-editor.ts new file mode 100644 index 0000000..4659ded --- /dev/null +++ b/src/hooks/use-data-source-editor.ts @@ -0,0 +1,77 @@ +import { useCallback, useEffect, useMemo, useState } from 'react' +import { DataSource } from '@/types/json-ui' + +interface UseDataSourceEditorParams { + dataSource: DataSource | null + allDataSources: DataSource[] + onSave: (dataSource: DataSource) => void + onOpenChange: (open: boolean) => void +} + +export function useDataSourceEditor({ + dataSource, + allDataSources, + onSave, + onOpenChange, +}: UseDataSourceEditorParams) { + const [editingSource, setEditingSource] = useState(dataSource) + + useEffect(() => { + setEditingSource(dataSource) + }, [dataSource]) + + const updateField = useCallback((field: K, value: DataSource[K]) => { + setEditingSource((prev) => { + if (!prev) return prev + return { ...prev, [field]: value } + }) + }, []) + + const addDependency = useCallback((depId: string) => { + setEditingSource((prev) => { + if (!prev || prev.type !== 'computed') return prev + const deps = prev.dependencies || [] + if (deps.includes(depId)) return prev + return { ...prev, dependencies: [...deps, depId] } + }) + }, []) + + const removeDependency = useCallback((depId: string) => { + setEditingSource((prev) => { + if (!prev || prev.type !== 'computed') return prev + const deps = prev.dependencies || [] + return { ...prev, dependencies: deps.filter((id) => id !== depId) } + }) + }, []) + + const handleSave = useCallback(() => { + if (!editingSource) return + onSave(editingSource) + onOpenChange(false) + }, [editingSource, onOpenChange, onSave]) + + const availableDeps = useMemo(() => { + if (!editingSource) return [] + return allDataSources.filter( + (ds) => ds.id !== editingSource.id && ds.type !== 'computed', + ) + }, [allDataSources, editingSource]) + + const selectedDeps = useMemo(() => editingSource?.dependencies || [], [editingSource]) + + const unselectedDeps = useMemo(() => { + if (!editingSource) return [] + return availableDeps.filter((ds) => !selectedDeps.includes(ds.id)) + }, [availableDeps, editingSource, selectedDeps]) + + return { + editingSource, + updateField, + addDependency, + removeDependency, + handleSave, + availableDeps, + selectedDeps, + unselectedDeps, + } +}