"use client"; import React, { useState, useCallback, useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Plus, Trash2, Database, ArrowRight, Settings } from "lucide-react"; import { DataMappingConfig, DataDirection, TableInfo, FieldMapping, InboundMapping, OutboundMapping, DATA_DIRECTION_OPTIONS, INSERT_MODE_OPTIONS, } from "@/types/external-call/DataMappingTypes"; import { FieldMappingEditor } from "./FieldMappingEditor"; interface DataMappingSettingsProps { config: DataMappingConfig; onConfigChange: (config: DataMappingConfig) => void; httpMethod: string; availableTables?: TableInfo[]; readonly?: boolean; } export const DataMappingSettings: React.FC = ({ config, onConfigChange, httpMethod, availableTables = [], readonly = false, }) => { const [localConfig, setLocalConfig] = useState(config); // 컴포넌트 변경 시 로컬 상태 동기화 useEffect(() => { setLocalConfig(config); }, [config]); // HTTP 메서드에 따른 권장 방향 결정 const getRecommendedDirection = useCallback((method: string): DataDirection => { const upperMethod = method.toUpperCase(); if (upperMethod === "GET") return "inbound"; if (["POST", "PUT", "PATCH"].includes(upperMethod)) return "outbound"; return "none"; }, []); // 방향 변경 핸들러 const handleDirectionChange = useCallback( (direction: DataDirection) => { const newConfig = { ...localConfig, direction, // 방향에 따라 불필요한 매핑 제거 inboundMapping: direction === "inbound" || direction === "bidirectional" ? localConfig.inboundMapping || { targetTable: "", fieldMappings: [], insertMode: "insert" as const, } : undefined, outboundMapping: direction === "outbound" || direction === "bidirectional" ? localConfig.outboundMapping || { sourceTable: "", fieldMappings: [], } : undefined, }; setLocalConfig(newConfig); onConfigChange(newConfig); }, [localConfig, onConfigChange], ); // Inbound 매핑 업데이트 const handleInboundMappingChange = useCallback( (mapping: Partial) => { const newConfig = { ...localConfig, inboundMapping: { ...localConfig.inboundMapping!, ...mapping, }, }; setLocalConfig(newConfig); onConfigChange(newConfig); }, [localConfig, onConfigChange], ); // Outbound 매핑 업데이트 const handleOutboundMappingChange = useCallback( (mapping: Partial) => { const newConfig = { ...localConfig, outboundMapping: { ...localConfig.outboundMapping!, ...mapping, }, }; setLocalConfig(newConfig); onConfigChange(newConfig); }, [localConfig, onConfigChange], ); // 필드 매핑 업데이트 (Inbound) const handleInboundFieldMappingsChange = useCallback( (fieldMappings: FieldMapping[]) => { handleInboundMappingChange({ fieldMappings }); }, [handleInboundMappingChange], ); // 필드 매핑 업데이트 (Outbound) const handleOutboundFieldMappingsChange = useCallback( (fieldMappings: FieldMapping[]) => { handleOutboundMappingChange({ fieldMappings }); }, [handleOutboundMappingChange], ); // 검증 함수 const isConfigValid = useCallback(() => { if (localConfig.direction === "none") return true; if ( (localConfig.direction === "inbound" || localConfig.direction === "bidirectional") && localConfig.inboundMapping ) { if (!localConfig.inboundMapping.targetTable) return false; if (localConfig.inboundMapping.fieldMappings.length === 0) return false; } if ( (localConfig.direction === "outbound" || localConfig.direction === "bidirectional") && localConfig.outboundMapping ) { if (!localConfig.outboundMapping.sourceTable) return false; if (localConfig.outboundMapping.fieldMappings.length === 0) return false; } return true; }, [localConfig]); const recommendedDirection = getRecommendedDirection(httpMethod); return ( 데이터 매핑 설정 {!isConfigValid() && 설정 필요} {isConfigValid() && localConfig.direction !== "none" && 설정 완료}

외부 API와 내부 테이블 간의 데이터 매핑을 설정합니다.

{/* 매핑 방향 선택 */}
{localConfig.direction !== recommendedDirection && recommendedDirection !== "none" && (

💡 {httpMethod} 요청에는 "{DATA_DIRECTION_OPTIONS.find((o) => o.value === recommendedDirection)?.label}" 방향이 권장됩니다.

)}
{/* 매핑 설정 탭 */} {localConfig.direction !== "none" && ( {(localConfig.direction === "inbound" || localConfig.direction === "bidirectional") && ( 외부 → 내부 )} {(localConfig.direction === "outbound" || localConfig.direction === "bidirectional") && ( 내부 → 외부 )} {/* Inbound 매핑 설정 */} {(localConfig.direction === "inbound" || localConfig.direction === "bidirectional") && (
{/* 키 필드 설정 (upsert/update 모드일 때) */} {localConfig.inboundMapping?.insertMode !== "insert" && (
handleInboundMappingChange({ keyFields: e.target.value .split(",") .map((s) => s.trim()) .filter(Boolean), }) } placeholder="id, code" disabled={readonly} />

업데이트/업서트 시 사용할 키 필드를 쉼표로 구분하여 입력하세요.

)} {/* 필드 매핑 에디터 */} {localConfig.inboundMapping?.targetTable && ( t.name === localConfig.inboundMapping?.targetTable)} readonly={readonly} /> )}
)} {/* Outbound 매핑 설정 */} {(localConfig.direction === "outbound" || localConfig.direction === "bidirectional") && (
{/* 소스 필터 조건 */}