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

196 lines
7.9 KiB
TypeScript
Raw Normal View History

'use client';
import React, { useState, useCallback } from 'react';
import { ChartConfig, QueryResult } from './types';
interface VehicleMapConfigPanelProps {
config?: ChartConfig;
queryResult?: QueryResult;
onConfigChange: (config: ChartConfig) => void;
}
/**
*
* - /
* - /
*/
export function VehicleMapConfigPanel({ config, queryResult, onConfigChange }: VehicleMapConfigPanelProps) {
const [currentConfig, setCurrentConfig] = useState<ChartConfig>(config || {});
// 설정 업데이트
const updateConfig = useCallback((updates: Partial<ChartConfig>) => {
const newConfig = { ...currentConfig, ...updates };
setCurrentConfig(newConfig);
onConfigChange(newConfig);
}, [currentConfig, onConfigChange]);
// 사용 가능한 컬럼 목록
const availableColumns = queryResult?.columns || [];
const sampleData = queryResult?.rows?.[0] || {};
return (
2025-10-22 13:40:15 +09:00
<div className="space-y-3">
<h4 className="text-xs font-semibold text-gray-800">🗺 </h4>
{/* 쿼리 결과가 없을 때 */}
{!queryResult && (
2025-10-22 13:40:15 +09:00
<div className="p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
<div className="text-yellow-800 text-xs">
💡 SQL .
</div>
</div>
)}
{/* 데이터 필드 매핑 */}
{queryResult && (
<>
{/* 지도 제목 */}
2025-10-22 13:40:15 +09:00
<div className="space-y-1.5">
<label className="block text-xs font-medium text-gray-700"> </label>
<input
type="text"
value={currentConfig.title || ''}
onChange={(e) => updateConfig({ title: e.target.value })}
placeholder="차량 위치 지도"
2025-10-22 13:40:15 +09:00
className="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-xs"
/>
</div>
{/* 위도 컬럼 설정 */}
2025-10-22 13:40:15 +09:00
<div className="space-y-1.5">
<label className="block text-xs font-medium text-gray-700">
(Latitude)
<span className="text-red-500 ml-1">*</span>
</label>
<select
value={currentConfig.latitudeColumn || ''}
onChange={(e) => updateConfig({ latitudeColumn: e.target.value })}
2025-10-22 13:40:15 +09:00
className="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-xs"
>
<option value=""></option>
{availableColumns.map((col) => (
<option key={col} value={col}>
{col} {sampleData[col] && `(예: ${sampleData[col]})`}
</option>
))}
</select>
</div>
{/* 경도 컬럼 설정 */}
2025-10-22 13:40:15 +09:00
<div className="space-y-1.5">
<label className="block text-xs font-medium text-gray-700">
(Longitude)
<span className="text-red-500 ml-1">*</span>
</label>
<select
value={currentConfig.longitudeColumn || ''}
onChange={(e) => updateConfig({ longitudeColumn: e.target.value })}
2025-10-22 13:40:15 +09:00
className="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-xs"
>
<option value=""></option>
{availableColumns.map((col) => (
<option key={col} value={col}>
{col} {sampleData[col] && `(예: ${sampleData[col]})`}
</option>
))}
</select>
</div>
{/* 라벨 컬럼 (선택사항) */}
2025-10-22 13:40:15 +09:00
<div className="space-y-1.5">
<label className="block text-xs font-medium text-gray-700">
( )
</label>
<select
value={currentConfig.labelColumn || ''}
onChange={(e) => updateConfig({ labelColumn: e.target.value })}
2025-10-22 13:40:15 +09:00
className="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-xs"
>
<option value=""> ()</option>
{availableColumns.map((col) => (
<option key={col} value={col}>
{col}
</option>
))}
</select>
</div>
{/* 상태 컬럼 (선택사항) */}
2025-10-22 13:40:15 +09:00
<div className="space-y-1.5">
<label className="block text-xs font-medium text-gray-700">
( )
</label>
<select
value={currentConfig.statusColumn || ''}
onChange={(e) => updateConfig({ statusColumn: e.target.value })}
2025-10-22 13:40:15 +09:00
className="w-full px-2 py-1.5 border border-gray-300 rounded-lg text-xs"
>
<option value=""> ()</option>
{availableColumns.map((col) => (
<option key={col} value={col}>
{col}
</option>
))}
</select>
</div>
2025-10-23 13:17:21 +09:00
{/* 날씨 정보 표시 옵션 */}
<div className="space-y-1.5">
<label className="flex items-center gap-2 text-xs font-medium text-gray-700 cursor-pointer">
<input
type="checkbox"
checked={currentConfig.showWeather || false}
onChange={(e) => updateConfig({ showWeather: e.target.checked })}
className="h-4 w-4 rounded border-gray-300 text-primary focus:ring-2 focus:ring-primary"
/>
<span> </span>
</label>
<p className="text-xs text-gray-500 ml-6">
</p>
</div>
<div className="space-y-1.5">
<label className="flex items-center gap-2 text-xs font-medium text-gray-700 cursor-pointer">
<input
type="checkbox"
checked={currentConfig.showWeatherAlerts || false}
onChange={(e) => updateConfig({ showWeatherAlerts: e.target.checked })}
className="h-4 w-4 rounded border-gray-300 text-primary focus:ring-2 focus:ring-primary"
/>
<span> </span>
</label>
<p className="text-xs text-gray-500 ml-6">
(/)
</p>
</div>
{/* 설정 미리보기 */}
<div className="p-3 bg-gray-50 rounded-lg">
2025-10-22 13:40:15 +09:00
<div className="text-xs font-medium text-gray-700 mb-2">📋 </div>
<div className="text-xs text-muted-foreground space-y-1">
<div><strong>:</strong> {currentConfig.latitudeColumn || '미설정'}</div>
<div><strong>:</strong> {currentConfig.longitudeColumn || '미설정'}</div>
<div><strong>:</strong> {currentConfig.labelColumn || '없음'}</div>
<div><strong>:</strong> {currentConfig.statusColumn || '없음'}</div>
2025-10-23 13:17:21 +09:00
<div><strong> :</strong> {currentConfig.showWeather ? '활성화' : '비활성화'}</div>
<div><strong> :</strong> {currentConfig.showWeatherAlerts ? '활성화' : '비활성화'}</div>
<div><strong> :</strong> {queryResult.rows.length}</div>
</div>
</div>
{/* 필수 필드 확인 */}
{(!currentConfig.latitudeColumn || !currentConfig.longitudeColumn) && (
<div className="p-3 bg-red-50 border border-red-200 rounded-lg">
2025-10-22 13:40:15 +09:00
<div className="text-red-800 text-xs">
.
</div>
</div>
)}
</>
)}
</div>
);
}