"use client"; import React, { useState, useEffect } from "react"; import { CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { ArrowLeft, ArrowRight, Table, Search, Loader2 } from "lucide-react"; import { toast } from "sonner"; // API import import { getTablesFromConnection, getBatchTablesWithColumns } from "@/lib/api/multiConnection"; // νƒ€μž… import import { Connection, TableInfo } from "@/lib/types/multiConnection"; interface TableStepProps { fromConnection?: Connection; toConnection?: Connection; fromTable?: TableInfo; toTable?: TableInfo; onSelectTable: (type: "from" | "to", table: TableInfo) => void; onNext: () => void; onBack: () => void; } /** * πŸ“‹ 2단계: ν…Œμ΄λΈ” 선택 * - FROM/TO ν…Œμ΄λΈ” 선택 * - ν…Œμ΄λΈ” 검색 κΈ°λŠ₯ * - 컬럼 수 정보 ν‘œμ‹œ */ const TableStep: React.FC = ({ fromConnection, toConnection, fromTable, toTable, onSelectTable, onNext, onBack, }) => { const [fromTables, setFromTables] = useState([]); const [toTables, setToTables] = useState([]); const [fromSearch, setFromSearch] = useState(""); const [toSearch, setToSearch] = useState(""); const [isLoadingFrom, setIsLoadingFrom] = useState(false); const [isLoadingTo, setIsLoadingTo] = useState(false); const [tableColumnCounts, setTableColumnCounts] = useState>({}); // FROM ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ (배치 쑰회) useEffect(() => { if (fromConnection) { const loadFromTables = async () => { try { setIsLoadingFrom(true); console.log("πŸš€ FROM ν…Œμ΄λΈ” 배치 쑰회 μ‹œμž‘"); // 배치 쑰회둜 ν…Œμ΄λΈ” 정보와 컬럼 수λ₯Ό ν•œλ²ˆμ— κ°€μ Έμ˜€κΈ° const batchResult = await getBatchTablesWithColumns(fromConnection.id); console.log("βœ… FROM ν…Œμ΄λΈ” 배치 쑰회 μ™„λ£Œ:", batchResult); // TableInfo ν˜•μ‹μœΌλ‘œ λ³€ν™˜ const tables: TableInfo[] = batchResult.map((item) => ({ tableName: item.tableName, displayName: item.displayName || item.tableName, })); setFromTables(tables); // 컬럼 수 정보λ₯Ό state에 μ €μž₯ const columnCounts: Record = {}; batchResult.forEach((item) => { columnCounts[`from_${item.tableName}`] = item.columnCount; }); setTableColumnCounts((prev) => ({ ...prev, ...columnCounts, })); console.log(`πŸ“Š FROM ν…Œμ΄λΈ” ${tables.length}개 λ‘œλ“œ μ™„λ£Œ, 컬럼 수:`, columnCounts); } catch (error) { console.error("FROM ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ μ‹€νŒ¨:", error); toast.error("μ†ŒμŠ€ ν…Œμ΄λΈ” λͺ©λ‘μ„ λΆˆλŸ¬μ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€."); } finally { setIsLoadingFrom(false); } }; loadFromTables(); } }, [fromConnection]); // TO ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ (배치 쑰회) useEffect(() => { if (toConnection) { const loadToTables = async () => { try { setIsLoadingTo(true); console.log("πŸš€ TO ν…Œμ΄λΈ” 배치 쑰회 μ‹œμž‘"); // 배치 쑰회둜 ν…Œμ΄λΈ” 정보와 컬럼 수λ₯Ό ν•œλ²ˆμ— κ°€μ Έμ˜€κΈ° const batchResult = await getBatchTablesWithColumns(toConnection.id); console.log("βœ… TO ν…Œμ΄λΈ” 배치 쑰회 μ™„λ£Œ:", batchResult); // TableInfo ν˜•μ‹μœΌλ‘œ λ³€ν™˜ const tables: TableInfo[] = batchResult.map((item) => ({ tableName: item.tableName, displayName: item.displayName || item.tableName, })); setToTables(tables); // 컬럼 수 정보λ₯Ό state에 μ €μž₯ const columnCounts: Record = {}; batchResult.forEach((item) => { columnCounts[`to_${item.tableName}`] = item.columnCount; }); setTableColumnCounts((prev) => ({ ...prev, ...columnCounts, })); console.log(`πŸ“Š TO ν…Œμ΄λΈ” ${tables.length}개 λ‘œλ“œ μ™„λ£Œ, 컬럼 수:`, columnCounts); } catch (error) { console.error("TO ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ μ‹€νŒ¨:", error); toast.error("λŒ€μƒ ν…Œμ΄λΈ” λͺ©λ‘μ„ λΆˆλŸ¬μ˜€λŠ”λ° μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€."); } finally { setIsLoadingTo(false); } }; loadToTables(); } }, [toConnection]); // ν…Œμ΄λΈ” 필터링 const filteredFromTables = fromTables.filter((table) => (table.displayName || table.tableName).toLowerCase().includes(fromSearch.toLowerCase()), ); const filteredToTables = toTables.filter((table) => (table.displayName || table.tableName).toLowerCase().includes(toSearch.toLowerCase()), ); const handleTableSelect = (type: "from" | "to", tableName: string) => { const tables = type === "from" ? fromTables : toTables; const table = tables.find((t) => t.tableName === tableName); if (table) { onSelectTable(type, table); } }; const canProceed = fromTable && toTable; const renderTableItem = (table: TableInfo, type: "from" | "to") => { const displayName = table.displayName && table.displayName !== table.tableName ? table.displayName : table.tableName; const columnCount = tableColumnCounts[`${type}_${table.tableName}`]; return (
{displayName} {columnCount !== undefined ? columnCount : table.columnCount || 0}개 컬럼 ); }; return ( <>
2단계: ν…Œμ΄λΈ” 선택

μ—°κ²°λœ λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μ†ŒμŠ€μ™€ λŒ€μƒ ν…Œμ΄λΈ”μ„ μ„ νƒν•˜μ„Έμš”.

{/* FROM ν…Œμ΄λΈ” 선택 */}

FROM ν…Œμ΄λΈ” (μ†ŒμŠ€)

{fromConnection?.name}
{/* 검색 */}
setFromSearch(e.target.value)} className="pl-9" />
{/* ν…Œμ΄λΈ” 선택 */} {isLoadingFrom ? (
ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ 쀑...
) : ( )} {fromTable && (
{fromTable.displayName || fromTable.tableName} πŸ“Š {tableColumnCounts[`from_${fromTable.tableName}`] || fromTable.columnCount || 0}개 컬럼
{fromTable.description &&

{fromTable.description}

}
)}
{/* TO ν…Œμ΄λΈ” 선택 */}

TO ν…Œμ΄λΈ” (λŒ€μƒ)

{toConnection?.name}
{/* 검색 */}
setToSearch(e.target.value)} className="pl-9" />
{/* ν…Œμ΄λΈ” 선택 */} {isLoadingTo ? (
ν…Œμ΄λΈ” λͺ©λ‘ λ‘œλ“œ 쀑...
) : ( )} {toTable && (
{toTable.displayName || toTable.tableName} πŸ“Š {tableColumnCounts[`to_${toTable.tableName}`] || toTable.columnCount || 0}개 컬럼
{toTable.description &&

{toTable.description}

}
)}
{/* ν…Œμ΄λΈ” λ§€ν•‘ ν‘œμ‹œ */} {fromTable && toTable && (
{fromTable.displayName || fromTable.tableName}
{tableColumnCounts[`from_${fromTable.tableName}`] || fromTable.columnCount || 0}개 컬럼
{toTable.displayName || toTable.tableName}
{tableColumnCounts[`to_${toTable.tableName}`] || toTable.columnCount || 0}개 컬럼
πŸ’‘ ν…Œμ΄λΈ” λ§€ν•‘: {fromTable.displayName || fromTable.tableName} β†’{" "} {toTable.displayName || toTable.tableName}
)} {/* λ„€λΉ„κ²Œμ΄μ…˜ λ²„νŠΌ */}
); }; export default TableStep;