"use client"; import React, { useEffect, useRef } from "react"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Badge } from "@/components/ui/badge"; import { Link, GripVertical } from "lucide-react"; // νƒ€μž… import import { ColumnInfo } from "@/lib/types/multiConnection"; interface FieldColumnProps { fields: ColumnInfo[]; type: "from" | "to"; selectedField: ColumnInfo | null; onFieldSelect: (field: ColumnInfo | null) => void; onFieldPositionUpdate: (fieldId: string, element: HTMLElement) => void; isFieldMapped: (field: ColumnInfo, type: "from" | "to") => boolean; onDragStart?: (field: ColumnInfo) => void; onDragEnd?: () => void; onDrop?: (targetField: ColumnInfo, sourceField: ColumnInfo) => void; isDragOver?: boolean; draggedField?: ColumnInfo | null; } /** * πŸ“‹ ν•„λ“œ 컬럼 μ»΄ν¬λ„ŒνŠΈ * - ν•„λ“œ λͺ©λ‘ ν‘œμ‹œ * - 선택 μƒνƒœ 관리 * - μœ„μΉ˜ 정보 μ—…λ°μ΄νŠΈ */ const FieldColumn: React.FC = ({ fields, type, selectedField, onFieldSelect, onFieldPositionUpdate, isFieldMapped, onDragStart, onDragEnd, onDrop, isDragOver, draggedField, }) => { const fieldRefs = useRef>({}); // ν•„λ“œ μœ„μΉ˜ μ—…λ°μ΄νŠΈ useEffect(() => { const updatePositions = () => { Object.entries(fieldRefs.current).forEach(([fieldId, element]) => { if (element) { onFieldPositionUpdate(fieldId, element); } }); }; // μ•½κ°„μ˜ 지연을 두어 DOM이 μ™„μ „νžˆ λ Œλ”λ§λœ ν›„ μœ„μΉ˜ μ—…λ°μ΄νŠΈ const timeoutId = setTimeout(updatePositions, 100); return () => clearTimeout(timeoutId); }, [fields.length]); // fields λ°°μ—΄ λŒ€μ‹  length만 μ˜μ‘΄μ„±μœΌλ‘œ μ‚¬μš© // λ“œλž˜κ·Έ μ•€ λ“œλ‘­ ν•Έλ“€λŸ¬ const handleDragStart = (e: React.DragEvent, field: ColumnInfo) => { if (type === "from" && onDragStart) { e.dataTransfer.setData("text/plain", JSON.stringify(field)); e.dataTransfer.effectAllowed = "copy"; onDragStart(field); } }; const handleDragEnd = (e: React.DragEvent) => { if (onDragEnd) { onDragEnd(); } }; const handleDragOver = (e: React.DragEvent) => { if (type === "to") { e.preventDefault(); e.dataTransfer.dropEffect = "copy"; } }; const handleDrop = (e: React.DragEvent, targetField: ColumnInfo) => { if (type === "to" && onDrop) { e.preventDefault(); // 이미 λ§€ν•‘λœ TO ν•„λ“œμΈμ§€ 확인 const isMapped = isFieldMapped(targetField, "to"); if (isMapped) { // 이미 λ§€ν•‘λœ ν•„λ“œμ—λŠ” λ“œλ‘­ν•  수 μ—†μŒμ„ μ‹œκ°μ μœΌλ‘œ ν‘œμ‹œ return; } try { const sourceFieldData = e.dataTransfer.getData("text/plain"); const sourceField = JSON.parse(sourceFieldData) as ColumnInfo; onDrop(targetField, sourceField); } catch (error) { console.error("λ“œλ‘­ 처리 쀑 였λ₯˜:", error); } } }; // ν•„λ“œ λ Œλ”λ§ const renderField = (field: ColumnInfo, index: number) => { const fieldId = `${type}_${field.columnName}`; const isSelected = selectedField?.columnName === field.columnName; const isMapped = isFieldMapped(field, type); const displayName = field.displayName || field.columnName; const isDragging = draggedField?.columnName === field.columnName; const isDropTarget = type === "to" && isDragOver && draggedField && !isMapped; const isBlockedDropTarget = type === "to" && isDragOver && draggedField && isMapped; return (
{ if (el) { fieldRefs.current[fieldId] = el; } }} className={`relative cursor-pointer rounded-lg border p-3 transition-all duration-200 ${ isDragging ? "border-primary bg-primary/20 scale-105 transform opacity-50 shadow-lg" : isSelected ? "border-primary bg-primary/10 shadow-md" : isMapped ? "border-green-500 bg-green-50 shadow-sm" : isBlockedDropTarget ? "border-red-400 bg-destructive/10 shadow-md" : isDropTarget ? "border-blue-400 bg-accent shadow-md" : "border-border hover:bg-muted/50 hover:shadow-sm" } `} draggable={type === "from" && !isMapped} onDragStart={(e) => handleDragStart(e, field)} onDragEnd={handleDragEnd} onDragOver={handleDragOver} onDrop={(e) => handleDrop(e, field)} onClick={() => onFieldSelect(isSelected ? null : field)} > {/* 연결점 ν‘œμ‹œ */}
{type === "from" && !isMapped && } {displayName} {isMapped && }
{field.webType || field.dataType || "unknown"}
{field.description &&

{field.description}

} {/* 선택 μƒνƒœ ν‘œμ‹œ */} {isSelected &&
}
); }; return (
{fields.map((field, index) => renderField(field, index))} {fields.length === 0 && (

ν•„λ“œκ°€ μ—†μŠ΅λ‹ˆλ‹€.

ν…Œμ΄λΈ”μ„ μ„ νƒν•΄μ£Όμ„Έμš”.

)}
); }; export default FieldColumn;