"use client"; import { motion, AnimatePresence } from "framer-motion"; import { useState, useEffect, useRef } from "react"; import type { Node } from "@xyflow/react"; interface LogicNodePanelProps { node: Node | null; nodes: Node[]; onClose: () => void; onDelete: (nodeId: string) => void; onUpdate: (nodeId: string, data: any) => void; } export default function LogicNodePanel({ node, nodes, onClose, onDelete, onUpdate }: LogicNodePanelProps) { const nodeData = node?.data as any; const nodeType = nodeData?.nodeType?.toLowerCase() || ''; const [name, setName] = useState(nodeData?.name || nodeData?.nodeName || "Logic"); const conditionTextareaRef = useRef(null); const whileConditionTextareaRef = useRef(null); const approvalMessageTextareaRef = useRef(null); // If/Else state const [condition, setCondition] = useState(nodeData?.condition || "input.score > 70"); // While state const [whileCondition, setWhileCondition] = useState(nodeData?.whileCondition || "iteration < 10"); const [maxIterations, setMaxIterations] = useState(nodeData?.maxIterations || "100"); // User Approval state const [approvalMessage, setApprovalMessage] = useState(nodeData?.approvalMessage || "Please review and approve this step"); const [timeoutMinutes, setTimeoutMinutes] = useState(nodeData?.timeoutMinutes || "30"); // Build available variables for conditions const getAvailableVariables = () => { const startNode = nodes.find(n => (n.data as any)?.nodeType === 'start'); const inputVariables = (startNode?.data as any)?.inputVariables || []; const previousNodes = nodes.filter(n => n.id !== node?.id && (n.data as any)?.nodeType !== 'note' && (n.data as any)?.nodeType !== 'start'); return { inputVars: inputVariables.map((v: any) => ({ name: v.name, path: `input.${v.name}`, description: v.description, type: v.type, })), nodeOutputs: previousNodes.map(n => ({ name: (n.data as any)?.nodeName || n.id, path: n.id.replace(/-/g, '_'), description: `Output from ${(n.data as any)?.nodeName || n.id}`, })), special: [ { name: 'lastOutput', path: 'lastOutput', description: 'Output from previous node' }, { name: 'iteration', path: 'iteration', description: 'Current iteration count (while loops only)' }, ] }; }; const insertVariable = (varPath: string, targetType: 'ifElse' | 'while' | 'approval') => { let textarea: HTMLTextAreaElement | null = null; let currentValue = ''; let setter: (value: string) => void; switch (targetType) { case 'ifElse': textarea = conditionTextareaRef.current; currentValue = condition; setter = setCondition; break; case 'while': textarea = whileConditionTextareaRef.current; currentValue = whileCondition; setter = setWhileCondition; break; case 'approval': textarea = approvalMessageTextareaRef.current; currentValue = approvalMessage; setter = setApprovalMessage; break; } if (!textarea) return; const start = textarea.selectionStart; const end = textarea.selectionEnd; const newValue = currentValue.substring(0, start) + varPath + currentValue.substring(end); setter(newValue); // Restore cursor position setTimeout(() => { textarea!.focus(); textarea!.setSelectionRange(start + varPath.length, start + varPath.length); }, 0); }; // Auto-save changes useEffect(() => { if (!node?.id) return; const timeoutId = setTimeout(() => { onUpdate(node.id, { name, nodeName: name, condition, whileCondition, maxIterations, approvalMessage, timeoutMinutes, }); }, 500); return () => clearTimeout(timeoutId); }, [name, condition, whileCondition, maxIterations, approvalMessage, timeoutMinutes]); const availableVars = getAvailableVariables(); return ( {node && ( {/* Header */}
setName(e.target.value)} className="text-label-large text-accent-black font-medium bg-transparent border-none outline-none focus:outline-none hover:bg-black-alpha-4 px-2 -ml-2 rounded-4 transition-colors" placeholder="Enter node name..." />

{nodeType.includes('if') ? 'Create conditions to branch your workflow' : nodeType.includes('while') ? 'Loop while a condition is true' : nodeType.includes('approval') ? 'Pause for a human to approve or reject a step' : 'Configure logic flow'}

{/* Form Fields */}
{/* If/Else Configuration */} {nodeType.includes('if') && ( <>