ERP-node/frontend/components/admin/dashboard/ElementConfigModal.tsx

170 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useState, useCallback } from 'react';
import { DashboardElement, ChartDataSource, ChartConfig, QueryResult } from './types';
import { QueryEditor } from './QueryEditor';
import { ChartConfigPanel } from './ChartConfigPanel';
interface ElementConfigModalProps {
element: DashboardElement;
isOpen: boolean;
onClose: () => void;
onSave: (element: DashboardElement) => void;
}
/**
* 요소 설정 모달 컴포넌트
* - 차트/위젯 데이터 소스 설정
* - 쿼리 에디터 통합
* - 차트 설정 패널 통합
*/
export function ElementConfigModal({ element, isOpen, onClose, onSave }: ElementConfigModalProps) {
const [dataSource, setDataSource] = useState<ChartDataSource>(
element.dataSource || { type: 'database', refreshInterval: 30000 }
);
const [chartConfig, setChartConfig] = useState<ChartConfig>(
element.chartConfig || {}
);
const [queryResult, setQueryResult] = useState<QueryResult | null>(null);
const [activeTab, setActiveTab] = useState<'query' | 'chart'>('query');
// 데이터 소스 변경 처리
const handleDataSourceChange = useCallback((newDataSource: ChartDataSource) => {
setDataSource(newDataSource);
}, []);
// 차트 설정 변경 처리
const handleChartConfigChange = useCallback((newConfig: ChartConfig) => {
setChartConfig(newConfig);
}, []);
// 쿼리 테스트 결과 처리
const handleQueryTest = useCallback((result: QueryResult) => {
setQueryResult(result);
// 쿼리 결과가 나오면 자동으로 차트 설정 탭으로 이동
if (result.rows.length > 0) {
setActiveTab('chart');
}
}, []);
// 저장 처리
const handleSave = useCallback(() => {
const updatedElement: DashboardElement = {
...element,
dataSource,
chartConfig,
};
onSave(updatedElement);
onClose();
}, [element, dataSource, chartConfig, onSave, onClose]);
// 모달이 열려있지 않으면 렌더링하지 않음
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg shadow-xl w-full max-w-4xl h-[80vh] flex flex-col">
{/* 모달 헤더 */}
<div className="flex justify-between items-center p-6 border-b border-gray-200">
<div>
<h2 className="text-xl font-semibold text-gray-800">
{element.title}
</h2>
<p className="text-sm text-gray-600 mt-1">
</p>
</div>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 text-2xl"
>
×
</button>
</div>
{/* 탭 네비게이션 */}
<div className="flex border-b border-gray-200">
<button
onClick={() => setActiveTab('query')}
className={`
px-6 py-3 text-sm font-medium border-b-2 transition-colors
${activeTab === 'query'
? 'border-blue-500 text-blue-600 bg-blue-50'
: 'border-transparent text-gray-500 hover:text-gray-700'}
`}
>
📝 &
</button>
<button
onClick={() => setActiveTab('chart')}
className={`
px-6 py-3 text-sm font-medium border-b-2 transition-colors
${activeTab === 'chart'
? 'border-blue-500 text-blue-600 bg-blue-50'
: 'border-transparent text-gray-500 hover:text-gray-700'}
`}
>
📊
{queryResult && (
<span className="ml-2 px-2 py-0.5 bg-green-100 text-green-800 text-xs rounded-full">
{queryResult.rows.length}
</span>
)}
</button>
</div>
{/* 탭 내용 */}
<div className="flex-1 overflow-auto p-6">
{activeTab === 'query' && (
<QueryEditor
dataSource={dataSource}
onDataSourceChange={handleDataSourceChange}
onQueryTest={handleQueryTest}
/>
)}
{activeTab === 'chart' && (
<ChartConfigPanel
config={chartConfig}
queryResult={queryResult}
onConfigChange={handleChartConfigChange}
/>
)}
</div>
{/* 모달 푸터 */}
<div className="flex justify-between items-center p-6 border-t border-gray-200">
<div className="text-sm text-gray-500">
{dataSource.query && (
<>
💾 : {dataSource.query.length > 50
? `${dataSource.query.substring(0, 50)}...`
: dataSource.query}
</>
)}
</div>
<div className="flex gap-3">
<button
onClick={onClose}
className="px-4 py-2 text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50"
>
</button>
<button
onClick={handleSave}
disabled={!dataSource.query || (!chartConfig.xAxis || !chartConfig.yAxis)}
className="
px-4 py-2 bg-blue-500 text-white rounded-lg
hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed
"
>
</button>
</div>
</div>
</div>
</div>
);
}