import React, { useState, useEffect } from 'react'; import HtmlEditorModal from './html.editor.modal.jsx'; function useDebouncedValue(value, delay = 300) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; } export default function SidebarPanel({ node, onClose, onOpenVariables, onCursorCapture, exposeHandle }) { if (!node) return null; const [step, setStep] = useState('category'); // 'category' | 'list' | 'settings' const [selectedCategoryId, setSelectedCategoryId] = useState(null); const [selectedItem, setSelectedItem] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const debouncedSearch = useDebouncedValue(searchQuery, 300); const [htmlEditorOpen, setHtmlEditorOpen] = useState(false); const [htmlEditorKey, setHtmlEditorKey] = useState(null); const [htmlEditorContent, setHtmlEditorContent] = useState(''); const nodeType = node?.type; const config = window.WAIC_WORKFLOW?.blocks?.[nodeType+'s'] || {}; const lang = window.WAIC_WORKFLOW?.lang || {}; const categories = Object.entries(config).map(([key, value]) => ({ id: key || '', name: value.name || '', desc: value.desc || '', items: value.list || [], })); const handleSettingChange = (key, value) => { if (!node || !node.data || !selectedItem) return; const currentValues = { ...node.data.settings, [key]: value, }; const errorKey = node.data.error || false; const filteredSettings = getVisibleSettings(selectedItem.settings, currentValues); onClose({ ...node, data: { ...node.data, settings: filteredSettings, error: errorKey === key ? false : errorKey, }, }); }; useEffect(() => { setSelectedItem(null); setSelectedCategoryId(null); setStep('category'); setSearchQuery(''); const { category, code } = node.data || {}; const safeCategory = category ?? ''; const categoryConfig = config[safeCategory] || config['']; setSearchQuery(''); if (code && categoryConfig?.list) { const found = categoryConfig.list.find((item) => item.code === code); if (found) { setSelectedCategoryId(safeCategory); setSelectedItem(found); setStep('settings'); return; } } setStep('category'); setSelectedCategoryId(null); setSelectedItem(null); }, [node?.id]); useEffect(() => { if (exposeHandle) { exposeHandle(handleSettingChange); } waicInitTooltips('.waic-sidebar-body'); }, [node]); useEffect(() => { if (step === 'category') setSelectedCategoryId(null); }, [step]); const handleCategorySelect = (catId) => { setSelectedCategoryId(catId); setStep('list'); onClose({ ...node, data: { ...node.data, type: nodeType, category: catId, error: false, }, }); }; const handleItemSelect = (item) => { setSelectedItem(item); setStep('settings'); onClose({ ...node, data: { ...node.data, type: nodeType, category: selectedCategoryId ?? 'un', code: item.code, label: item.name, settings: getVisibleSettings(item.settings, {}), error: false, }, }); }; const getVisibleSettings = (settingsConfig, values) => { const result = {}; const effectiveValues = getEffectiveSettingsValues(settingsConfig, values); Object.entries(settingsConfig).forEach(([key, setting]) => { if (setting.inner) return; if (!shouldShowSetting(setting, effectiveValues)) return; //result[key] = effectiveValues[key]; if (key in settingsConfig) { result[key] = effectiveValues[key]; } if (setting.add) { setting.add.forEach((addKey) => { const addSetting = settingsConfig[addKey]; if (addSetting && shouldShowSetting(addSetting, effectiveValues)) { result[addKey] = effectiveValues[addKey]; } }); } }); return result; }; const renderLabel = (setting, key) => { if (setting.label !== '') { return (
{setting.label} {setting.tooltip && ( info )} {setting.html && (
{ setHtmlEditorKey(key); setHtmlEditorContent(node.data?.settings?.[key] ?? ''); setHtmlEditorOpen(true); }}> HTML
)} {setting.variables && (
onOpenVariables(key)}>{lang?.['variables'] || ''}
)} {setting.copy && (
waicCopyText(node.data?.settings?.[key] ?? '')}>{lang?.['copy'] || ''}
)}
); } return null; }; const renderSidebarDesc = (item) => { const desc = item?.desc ?? ''; if (desc !== '') { return (
{desc}
); } return null; }; const renderSettingField = (key, setting) => { const value = node.data?.settings?.[key]; switch (setting.type) { case 'input': return ( <> {renderLabel(setting, key)}
handleSettingChange(key, e.target.value)} onFocus={(e) => onCursorCapture(e, key)} onClick={(e) => onCursorCapture(e, key)} onKeyUp={(e) => onCursorCapture(e, key)} />
); case 'select': return ( <> {renderLabel(setting, key)}
); case 'multiple': return ( <> {renderLabel(setting, key)}
); case 'number': return ( <> {renderLabel(setting, key)}
handleSettingChange(key, e.target.value)} />
); case 'datetime': return ( <> {renderLabel(setting, key)}
handleSettingChange(key, e.target.value)} />
); case 'date': return ( <> {renderLabel(setting, key)}
handleSettingChange(key, e.target.value)} />
); case 'time': return ( <> {renderLabel(setting, key)}
handleSettingChange(key, e.target.value)} />
); case 'textarea': return ( <> {renderLabel(setting, key)}