"use client"; import React, { useState, useEffect, useCallback } from "react"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Separator } from "@/components/ui/separator"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Settings, Clock, Info, Workflow, Plus, Trash2, GripVertical, ChevronUp, ChevronDown } from "lucide-react"; import { ComponentData } from "@/types/screen"; import { getNodeFlows, NodeFlow } from "@/lib/api/nodeFlows"; interface ImprovedButtonControlConfigPanelProps { component: ComponentData; onUpdateProperty: (path: string, value: any) => void; } // 다중 제어 설정 인터페이스 interface FlowControlConfig { id: string; flowId: number; flowName: string; executionTiming: "before" | "after" | "replace"; order: number; } /** * 🔥 다중 제어 지원 버튼 설정 패널 * * 기능: * - 여러 개의 노드 플로우 선택 및 순서 지정 * - 각 플로우별 실행 타이밍 설정 * - 드래그앤드롭 또는 버튼으로 순서 변경 */ export const ImprovedButtonControlConfigPanel: React.FC = ({ component, onUpdateProperty, }) => { const config = component.webTypeConfig || {}; const dataflowConfig = config.dataflowConfig || {}; // 다중 제어 설정 (배열) const flowControls: FlowControlConfig[] = dataflowConfig.flowControls || []; // 🔥 State 관리 const [flows, setFlows] = useState([]); const [loading, setLoading] = useState(false); // 🔥 플로우 목록 로딩 useEffect(() => { if (config.enableDataflowControl) { loadFlows(); } }, [config.enableDataflowControl]); /** * 🔥 플로우 목록 로드 */ const loadFlows = async () => { try { setLoading(true); console.log("🔍 플로우 목록 로딩..."); const flowList = await getNodeFlows(); setFlows(flowList); console.log(`✅ 플로우 ${flowList.length}개 로딩 완료`); } catch (error) { console.error("❌ 플로우 목록 로딩 실패:", error); setFlows([]); } finally { setLoading(false); } }; /** * 🔥 제어 추가 */ const handleAddControl = useCallback(() => { const newControl: FlowControlConfig = { id: `control_${Date.now()}`, flowId: 0, flowName: "", executionTiming: "after", order: flowControls.length + 1, }; const updatedControls = [...flowControls, newControl]; updateFlowControls(updatedControls); }, [flowControls]); /** * 🔥 제어 삭제 */ const handleRemoveControl = useCallback( (controlId: string) => { const updatedControls = flowControls .filter((c) => c.id !== controlId) .map((c, index) => ({ ...c, order: index + 1 })); updateFlowControls(updatedControls); }, [flowControls], ); /** * 🔥 제어 플로우 선택 */ const handleFlowSelect = useCallback( (controlId: string, flowId: string) => { const selectedFlow = flows.find((f) => f.flowId.toString() === flowId); if (selectedFlow) { const updatedControls = flowControls.map((c) => c.id === controlId ? { ...c, flowId: selectedFlow.flowId, flowName: selectedFlow.flowName } : c, ); updateFlowControls(updatedControls); } }, [flows, flowControls], ); /** * 🔥 실행 타이밍 변경 */ const handleTimingChange = useCallback( (controlId: string, timing: "before" | "after" | "replace") => { const updatedControls = flowControls.map((c) => (c.id === controlId ? { ...c, executionTiming: timing } : c)); updateFlowControls(updatedControls); }, [flowControls], ); /** * 🔥 순서 위로 이동 */ const handleMoveUp = useCallback( (controlId: string) => { const index = flowControls.findIndex((c) => c.id === controlId); if (index > 0) { const updatedControls = [...flowControls]; [updatedControls[index - 1], updatedControls[index]] = [updatedControls[index], updatedControls[index - 1]]; // 순서 번호 재정렬 updatedControls.forEach((c, i) => (c.order = i + 1)); updateFlowControls(updatedControls); } }, [flowControls], ); /** * 🔥 순서 아래로 이동 */ const handleMoveDown = useCallback( (controlId: string) => { const index = flowControls.findIndex((c) => c.id === controlId); if (index < flowControls.length - 1) { const updatedControls = [...flowControls]; [updatedControls[index], updatedControls[index + 1]] = [updatedControls[index + 1], updatedControls[index]]; // 순서 번호 재정렬 updatedControls.forEach((c, i) => (c.order = i + 1)); updateFlowControls(updatedControls); } }, [flowControls], ); /** * 🔥 제어 목록 업데이트 (백엔드 호환성 유지) */ const updateFlowControls = (controls: FlowControlConfig[]) => { // 첫 번째 제어를 기존 형식으로도 저장 (하위 호환성) const firstValidControl = controls.find((c) => c.flowId > 0); onUpdateProperty("webTypeConfig.dataflowConfig", { ...dataflowConfig, // 기존 형식 (하위 호환성) selectedDiagramId: firstValidControl?.flowId || null, selectedRelationshipId: null, flowConfig: firstValidControl ? { flowId: firstValidControl.flowId, flowName: firstValidControl.flowName, executionTiming: firstValidControl.executionTiming, contextData: {}, } : null, // 새로운 다중 제어 형식 flowControls: controls, }); }; return (
{/* 🔥 제어관리 활성화 스위치 */}

버튼 클릭 시 추가 작업을 자동으로 실행합니다

onUpdateProperty("webTypeConfig.enableDataflowControl", checked)} />
{/* 🔥 제어관리가 활성화된 경우에만 설정 표시 */} {config.enableDataflowControl && (
{/* 제어 목록 헤더 */}
{/* 제어 목록 */} {flowControls.length === 0 ? (

등록된 제어가 없습니다

) : (
{flowControls.map((control, index) => ( handleFlowSelect(control.id, flowId)} onTimingChange={(timing) => handleTimingChange(control.id, timing)} onMoveUp={() => handleMoveUp(control.id)} onMoveDown={() => handleMoveDown(control.id)} onRemove={() => handleRemoveControl(control.id)} /> ))}
)} {/* 안내 메시지 */} {flowControls.length > 0 && (

다중 제어 실행 정보:

• 제어는 위에서 아래 순서대로 순차 실행됩니다

• 각 제어는 독립 트랜잭션으로 처리됩니다

• 이전 제어 실패 시 다음 제어는 실행되지 않습니다

)}
)}
); }; /** * 🔥 개별 제어 아이템 컴포넌트 */ const FlowControlItem: React.FC<{ control: FlowControlConfig; flows: NodeFlow[]; loading: boolean; isFirst: boolean; isLast: boolean; onFlowSelect: (flowId: string) => void; onTimingChange: (timing: "before" | "after" | "replace") => void; onMoveUp: () => void; onMoveDown: () => void; onRemove: () => void; }> = ({ control, flows, loading, isFirst, isLast, onFlowSelect, onTimingChange, onMoveUp, onMoveDown, onRemove }) => { return (
{/* 순서 표시 및 이동 버튼 */}
{control.order}
{/* 플로우 선택 및 설정 */}
{/* 플로우 선택 */} {/* 실행 타이밍 */}
{/* 삭제 버튼 */}
); };