"use client"; import { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { toast } from "sonner"; import { Plus, ArrowRight, Trash2, Pencil, GitBranch, RefreshCw } from "lucide-react"; import { getDataFlows, createDataFlow, updateDataFlow, deleteDataFlow, DataFlow, } from "@/lib/api/screenGroup"; interface DataFlowPanelProps { groupId?: number; screenId?: number; screens?: Array<{ screen_id: number; screen_name: string }>; } export default function DataFlowPanel({ groupId, screenId, screens = [] }: DataFlowPanelProps) { // 상태 관리 const [dataFlows, setDataFlows] = useState([]); const [loading, setLoading] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); const [selectedFlow, setSelectedFlow] = useState(null); const [formData, setFormData] = useState({ source_screen_id: 0, source_action: "", target_screen_id: 0, target_action: "", data_mapping: "", flow_type: "unidirectional", flow_label: "", condition_expression: "", is_active: "Y", }); // 데이터 로드 const loadDataFlows = useCallback(async () => { setLoading(true); try { const response = await getDataFlows(groupId); if (response.success && response.data) { setDataFlows(response.data); } } catch (error) { console.error("데이터 흐름 로드 실패:", error); } finally { setLoading(false); } }, [groupId]); useEffect(() => { loadDataFlows(); }, [loadDataFlows]); // 모달 열기 const openModal = (flow?: DataFlow) => { if (flow) { setSelectedFlow(flow); setFormData({ source_screen_id: flow.source_screen_id, source_action: flow.source_action || "", target_screen_id: flow.target_screen_id, target_action: flow.target_action || "", data_mapping: flow.data_mapping ? JSON.stringify(flow.data_mapping, null, 2) : "", flow_type: flow.flow_type, flow_label: flow.flow_label || "", condition_expression: flow.condition_expression || "", is_active: flow.is_active, }); } else { setSelectedFlow(null); setFormData({ source_screen_id: screenId || 0, source_action: "", target_screen_id: 0, target_action: "", data_mapping: "", flow_type: "unidirectional", flow_label: "", condition_expression: "", is_active: "Y", }); } setIsModalOpen(true); }; // 저장 const handleSave = async () => { if (!formData.source_screen_id || !formData.target_screen_id) { toast.error("소스 화면과 타겟 화면을 선택해주세요."); return; } try { let dataMappingJson = null; if (formData.data_mapping) { try { dataMappingJson = JSON.parse(formData.data_mapping); } catch { toast.error("데이터 매핑 JSON 형식이 올바르지 않습니다."); return; } } const payload = { group_id: groupId, source_screen_id: formData.source_screen_id, source_action: formData.source_action || null, target_screen_id: formData.target_screen_id, target_action: formData.target_action || null, data_mapping: dataMappingJson, flow_type: formData.flow_type, flow_label: formData.flow_label || null, condition_expression: formData.condition_expression || null, is_active: formData.is_active, }; let response; if (selectedFlow) { response = await updateDataFlow(selectedFlow.id, payload); } else { response = await createDataFlow(payload); } if (response.success) { toast.success(selectedFlow ? "데이터 흐름이 수정되었습니다." : "데이터 흐름이 추가되었습니다."); setIsModalOpen(false); loadDataFlows(); } else { toast.error(response.message || "저장에 실패했습니다."); } } catch (error) { toast.error("저장 중 오류가 발생했습니다."); } }; // 삭제 const handleDelete = async (id: number) => { if (!confirm("이 데이터 흐름을 삭제하시겠습니까?")) return; try { const response = await deleteDataFlow(id); if (response.success) { toast.success("데이터 흐름이 삭제되었습니다."); loadDataFlows(); } else { toast.error(response.message || "삭제에 실패했습니다."); } } catch (error) { toast.error("삭제 중 오류가 발생했습니다."); } }; // 액션 옵션 const sourceActions = [ { value: "click", label: "클릭" }, { value: "submit", label: "제출" }, { value: "select", label: "선택" }, { value: "change", label: "변경" }, { value: "doubleClick", label: "더블클릭" }, ]; const targetActions = [ { value: "open", label: "열기" }, { value: "load", label: "로드" }, { value: "refresh", label: "새로고침" }, { value: "save", label: "저장" }, { value: "filter", label: "필터" }, ]; return (
{/* 헤더 */}

데이터 흐름

{/* 설명 */}

화면 간 데이터 전달 흐름을 정의합니다. (예: 목록 화면에서 행 클릭 시 상세 화면 열기)

{/* 흐름 목록 */} {loading ? (
) : dataFlows.length === 0 ? (

정의된 데이터 흐름이 없습니다

) : (
{dataFlows.map((flow) => (
{/* 소스 화면 */}
{flow.source_screen_name || `화면 ${flow.source_screen_id}`} {flow.source_action && ( {flow.source_action} )}
{/* 화살표 */}
{flow.flow_type === "bidirectional" && ( )}
{/* 타겟 화면 */}
{flow.target_screen_name || `화면 ${flow.target_screen_id}`} {flow.target_action && ( {flow.target_action} )}
{/* 라벨 */} {flow.flow_label && ( {flow.flow_label} )}
{/* 액션 버튼 */}
))}
)} {/* 추가/수정 모달 */} {selectedFlow ? "데이터 흐름 수정" : "데이터 흐름 추가"} 화면 간 데이터 전달 흐름을 설정합니다
{/* 소스 화면 */}
{/* 타겟 화면 */}
{/* 흐름 설정 */}
setFormData({ ...formData, flow_label: e.target.value })} placeholder="예: 상세 보기" className="h-8 text-xs sm:h-10 sm:text-sm" />
{/* 데이터 매핑 */}