"use client"; import React, { useState } from "react"; import { ChartDataSource } from "@/components/admin/dashboard/types"; import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Plus, Trash2, Database, Globe } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import MultiApiConfig from "./MultiApiConfig"; import MultiDatabaseConfig from "./MultiDatabaseConfig"; interface MultiDataSourceConfigProps { dataSources: ChartDataSource[]; onChange: (dataSources: ChartDataSource[]) => void; onTestResult?: (result: { columns: string[]; rows: any[] }, dataSourceId: string) => void; } export default function MultiDataSourceConfig({ dataSources = [], onChange, onTestResult, }: MultiDataSourceConfigProps) { const [activeTab, setActiveTab] = useState( dataSources.length > 0 ? dataSources[0].id || "0" : "new" ); const [previewData, setPreviewData] = useState([]); const [showPreview, setShowPreview] = useState(false); const [showAddMenu, setShowAddMenu] = useState(false); // 새 데이터 소스 추가 (타입 지정) const handleAddDataSource = (type: "api" | "database") => { const newId = Date.now().toString(); const newSource: ChartDataSource = { id: newId, name: `${type === "api" ? "REST API" : "Database"} ${dataSources.length + 1}`, type, }; onChange([...dataSources, newSource]); setActiveTab(newId); setShowAddMenu(false); }; // 데이터 소스 삭제 const handleDeleteDataSource = (id: string) => { const filtered = dataSources.filter((ds) => ds.id !== id); onChange(filtered); // 삭제 후 첫 번째 탭으로 이동 if (filtered.length > 0) { setActiveTab(filtered[0].id || "0"); } else { setActiveTab("new"); } }; // 데이터 소스 업데이트 const handleUpdateDataSource = (id: string, updates: Partial) => { const updated = dataSources.map((ds) => ds.id === id ? { ...ds, ...updates } : ds ); onChange(updated); }; return (
{/* 헤더 */}

데이터 소스 관리

여러 데이터 소스를 연결하여 데이터를 통합할 수 있습니다

handleAddDataSource("api")}> REST API 추가 handleAddDataSource("database")}> Database 추가
{/* 데이터 소스가 없는 경우 */} {dataSources.length === 0 ? (

연결된 데이터 소스가 없습니다

handleAddDataSource("api")}> REST API 추가 handleAddDataSource("database")}> Database 추가
) : ( /* 탭 UI */ {dataSources.map((ds, index) => ( {ds.name || `소스 ${index + 1}`} ))} {dataSources.map((ds, index) => ( {/* 데이터 소스 기본 정보 */}
{/* 이름 */}
handleUpdateDataSource(ds.id!, { name: e.target.value }) } placeholder="예: 기상특보, 교통정보" className="h-8 text-xs" />
{/* 타입 선택 */}
handleUpdateDataSource(ds.id!, { type: value }) } >
{/* 삭제 버튼 */}
{/* 지도 표시 방식 선택 (지도 위젯만) */}
handleUpdateDataSource(ds.id!, { mapDisplayType: value as "auto" | "marker" | "polygon" }) } className="flex gap-4" >

{ds.mapDisplayType === "marker" && "모든 데이터를 마커로 표시합니다"} {ds.mapDisplayType === "polygon" && "모든 데이터를 영역(폴리곤)으로 표시합니다"} {(!ds.mapDisplayType || ds.mapDisplayType === "auto") && "데이터에 coordinates가 있으면 영역, 없으면 마커로 자동 표시"}

{/* 타입별 설정 */} {ds.type === "api" ? ( handleUpdateDataSource(ds.id!, updates)} onTestResult={(data) => { setPreviewData(data); setShowPreview(true); // 부모로 테스트 결과 전달 (차트 설정용) if (onTestResult && data.length > 0 && ds.id) { const columns = Object.keys(data[0]); onTestResult({ columns, rows: data }, ds.id); } }} /> ) : ( handleUpdateDataSource(ds.id!, updates)} onTestResult={(data) => { // 부모로 테스트 결과 전달 (차트 설정용) if (onTestResult && data.length > 0 && ds.id) { const columns = Object.keys(data[0]); onTestResult({ columns, rows: data }, ds.id); } }} /> )}
))}
)} {/* 지도 미리보기 */} {showPreview && previewData.length > 0 && (
데이터 미리보기 ({previewData.length}건)

"적용" 버튼을 눌러 지도에 표시하세요

{previewData.map((item, index) => { const hasLatLng = (item.lat || item.latitude) && (item.lng || item.longitude); const hasCoordinates = item.coordinates && Array.isArray(item.coordinates); return (
{item.name || item.title || item.area || item.region || `항목 ${index + 1}`}
{(item.status || item.level) && (
{item.status || item.level}
)}
{hasLatLng && (
📍 마커: ({item.lat || item.latitude}, {item.lng || item.longitude})
)} {hasCoordinates && (
🔷 영역: {item.coordinates.length}개 좌표
)} {(item.type || item.description) && (
{item.type && `${item.type} `} {item.description && item.description !== item.type && `- ${item.description}`}
)}
); })}
)}
); }