import { useState } from 'react' import { decimalToDMS } from '@common/utils/coordinates' import { ComboBox } from '@common/components/ui/ComboBox' import { ALL_MODELS } from './OilSpillView' import type { PredictionModel } from './OilSpillView' interface PredictionInputSectionProps { expanded: boolean onToggle: () => void incidentCoord: { lon: number; lat: number } onCoordChange: (coord: { lon: number; lat: number }) => void onMapSelectClick: () => void onRunSimulation: () => void isRunningSimulation: boolean selectedModels: Set onModelsChange: (models: Set) => void predictionTime: number onPredictionTimeChange: (time: number) => void spillType: string onSpillTypeChange: (type: string) => void oilType: string onOilTypeChange: (type: string) => void spillAmount: number onSpillAmountChange: (amount: number) => void } const PredictionInputSection = ({ expanded, onToggle, incidentCoord, onCoordChange, onMapSelectClick, onRunSimulation, isRunningSimulation, selectedModels, onModelsChange, predictionTime, onPredictionTimeChange, spillType, onSpillTypeChange, oilType, onOilTypeChange, spillAmount, onSpillAmountChange, }: PredictionInputSectionProps) => { const [inputMode, setInputMode] = useState<'direct' | 'upload'>('direct') const [uploadedImage, setUploadedImage] = useState(null) const [uploadedFileName, setUploadedFileName] = useState('') const handleImageUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { setUploadedFileName(file.name) const reader = new FileReader() reader.onload = (event) => { setUploadedImage(event.target?.result as string) } reader.readAsDataURL(file) } } const removeUploadedImage = () => { setUploadedImage(null) setUploadedFileName('') } return (

예측정보 입력

{expanded ? '▼' : '▶'}
{expanded && (
{/* Input Mode Selection */}
{/* Direct Input Mode */} {inputMode === 'direct' && ( <> )} {/* Image Upload Mode */} {inputMode === 'upload' && ( <> {}} options={[ { value: '', label: '여수 유조선 충돌 (INC-0042)' }, { value: 'INC-0042', label: '여수 유조선 충돌 (INC-0042)' } ]} placeholder="사고 선택" /> {/* Upload Success Message */} {uploadedImage && (
내 이미지가 업로드됨
)} {/* File Upload Area */} {!uploadedImage ? ( ) : (
📄 {uploadedFileName || 'example_plot_0.gif'}
)} {/* Dropdowns */}
{}} options={[ { value: '', label: '유출회사' }, { value: 'company1', label: '회사A' }, { value: 'company2', label: '회사B' } ]} placeholder="유출회사" /> {}} options={[ { value: '', label: '예상시각' }, { value: '09:00', label: '09:00' }, { value: '12:00', label: '12:00' } ]} placeholder="예상시각" />
)} {/* Coordinates + Map Button */}
{ const value = e.target.value === '' ? 0 : parseFloat(e.target.value) onCoordChange({ ...incidentCoord, lat: isNaN(value) ? 0 : value }) }} placeholder="위도°" /> { const value = e.target.value === '' ? 0 : parseFloat(e.target.value) onCoordChange({ ...incidentCoord, lon: isNaN(value) ? 0 : value }) }} placeholder="경도°" />
{/* 도분초 표시 */} {incidentCoord && !isNaN(incidentCoord.lat) && !isNaN(incidentCoord.lon) && (
{decimalToDMS(incidentCoord.lat, true)} / {decimalToDMS(incidentCoord.lon, false)}
)}
{/* Oil Type + Oil Kind */}
{/* Volume + Unit + Duration */}
onSpillAmountChange(parseInt(e.target.value) || 0)} /> {}} options={[ { value: 'kL', label: 'kL' }, { value: 'ton', label: 'Ton' }, { value: 'barrel', label: '배럴' } ]} /> onPredictionTimeChange(parseInt(v))} options={[ { value: '6', label: '6시간' }, { value: '12', label: '12시간' }, { value: '24', label: '24시간' }, { value: '48', label: '48시간' }, { value: '72', label: '72시간' } ]} />
{/* Image Analysis Note (Upload Mode Only) */} {inputMode === 'upload' && uploadedImage && (
📊 이미지 내 확산경로를 분석하였습니다. 각 방제요소 가이드 참고하세요.
)} {/* Divider */}
{/* Model Selection (다중 선택) */}
{([ { id: 'KOSPS' as PredictionModel, color: 'var(--cyan)' }, { id: 'POSEIDON' as PredictionModel, color: 'var(--red)' }, { id: 'OpenDrift' as PredictionModel, color: 'var(--blue)' }, ] as const).map(m => (
{ const next = new Set(selectedModels) if (next.has(m.id)) { next.delete(m.id) } else { next.add(m.id) } onModelsChange(next) }} > {m.id}
))}
{ if (selectedModels.size === ALL_MODELS.length) { onModelsChange(new Set(['KOSPS'])) } else { onModelsChange(new Set(ALL_MODELS)) } }} > 앙상블
{/* Run Button */}
)}
) } export default PredictionInputSection