import { useState, useEffect, useRef } from 'react' import L from 'leaflet' import 'leaflet/dist/leaflet.css' import type { ScatDetail } from './scatTypes' // ═══ Popup Map (Leaflet) ═══ function PopupMap({ lat, lng, esi, esiCol, code, name }: { lat: number; lng: number; esi: string; esiCol: string; code: string; name: string }) { const containerRef = useRef(null) const mapRef = useRef(null) useEffect(() => { if (!containerRef.current) return // 이전 맵 제거 if (mapRef.current) { mapRef.current.remove(); mapRef.current = null } const map = L.map(containerRef.current, { center: [lat, lng], zoom: 15, zoomControl: false, attributionControl: false, }) L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { maxZoom: 19 }).addTo(map) L.control.zoom({ position: 'topright' }).addTo(map) // 해안 구간 라인 (시뮬레이션) const segLine: [number, number][] = [ [lat - 0.002, lng - 0.004], [lat - 0.001, lng - 0.002], [lat, lng], [lat + 0.001, lng + 0.002], [lat + 0.002, lng + 0.004], ] L.polyline(segLine, { color: esiCol, weight: 5, opacity: 0.8 }).addTo(map) // 조사 경로 라인 const surveyRoute: [number, number][] = [ [lat - 0.0015, lng - 0.003], [lat - 0.0005, lng - 0.001], [lat + 0.0005, lng + 0.001], [lat + 0.0015, lng + 0.003], ] L.polyline(surveyRoute, { color: '#3b82f6', weight: 2, opacity: 0.6, dashArray: '6, 4' }).addTo(map) // 메인 마커 L.circleMarker([lat, lng], { radius: 10, fillColor: esiCol, color: '#fff', weight: 2, fillOpacity: 0.9, }).bindTooltip( `
${code} ${name}
ESI ${esi}
`, { permanent: true, direction: 'top', offset: [0, -12], className: 'scat-map-tooltip' } ).addTo(map) // 접근 포인트 L.circleMarker([lat - 0.0015, lng - 0.003], { radius: 6, fillColor: '#eab308', color: '#eab308', weight: 1, fillOpacity: 0.7, }).bindTooltip('접근 포인트', { direction: 'bottom', className: 'scat-map-tooltip' }).addTo(map) mapRef.current = map return () => { map.remove(); mapRef.current = null } }, [lat, lng, esi, esiCol, code, name]) return
} // ═══ SCAT Popup Modal ═══ interface ScatPopupProps { data: ScatDetail | null segCode: string onClose: () => void } function ScatPopup({ data, segCode, onClose, }: ScatPopupProps) { const [popTab, setPopTab] = useState(0) useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', handler) return () => document.removeEventListener('keydown', handler) }, [onClose]) if (!data) return null return (
e.stopPropagation()} > {/* Header */}
{data.code} {data.name} ESI {data.esi}
{/* Tabs */}
{['해안정보', '조사 이력'].map((label, i) => ( ))}
{/* Body */}
{popTab === 0 && (
{/* Left column */}
{/* 해안 조사 사진 */}
{`${segCode} { const target = e.currentTarget target.style.display = 'none' const fallback = target.nextElementSibling as HTMLElement if (fallback) fallback.style.display = 'flex' }} />
📷 사진 없음
{segCode}
{/* Survey Info */}
🏖 해안 기본정보
{[ ['유형', data.type, ''], ['기질', data.substrate, data.esiColor === '#dc2626' || data.esiColor === '#991b1b' ? 'text-status-red' : data.esiColor === '#f97316' ? 'text-status-orange' : ''], ['구간 길이', data.length, ''], ['민감도', data.sensitivity, data.sensitivity === '상' || data.sensitivity === '최상' ? 'text-status-red' : data.sensitivity === '중' ? 'text-status-orange' : 'text-status-green'], ['조사 상태', data.status, data.status === '완료' ? 'text-status-green' : data.status === '진행중' ? 'text-status-orange' : ''], ['접근성', data.access, ''], ['접근 포인트', data.accessPt, ''], ].map(([k, v, cls], i) => (
{k} {v}
))}
{/* Sensitive Resources */}
🌿 민감 자원
{data.sensitive.map((s, i) => (
{s.t} {s.v}
))}
{/* Cleanup Methods */}
🧹 방제 방법
{data.cleanup.map((c, i) => ( {c} ))}
{/* End Criteria */}
✅ 방제 종료 기준
{data.endCriteria.map((e, i) => (
{e}
))}
{/* Notes */}
📝 참고사항
{data.notes.map((n, i) => (
{n}
))}
{/* Right column - Satellite map */}
{/* Leaflet Map */}
{/* Legend */}
{[ { color: '#dc2626', label: 'ESI 고위험 구간' }, { color: '#f97316', label: 'ESI 중위험 구간' }, { color: '#22c55e', label: 'ESI 저위험 구간' }, { color: '#3b82f6', label: '조사 경로' }, { color: '#eab308', label: '접근 포인트' }, ].map((item, i) => (
{item.label}
))}
{/* Coordinates */}
📍 좌표 정보
{[ ['시작점 위도', `${data.lat.toFixed(4)}°N`], ['시작점 경도', `${data.lng.toFixed(4)}°E`], ['끝점 위도', `${(data.lat + 0.005).toFixed(4)}°N`], ['끝점 경도', `${(data.lng + 0.008).toFixed(4)}°E`], ].map(([k, v], i) => (
{k} {v}
))}
{/* Survey parameters */}
⚙ 조사 파라미터
{[ ['조사 일시', '2026-01-15 10:30'], ['조사팀', '제주해경 방제과'], ['기상 상태', '맑음, 풍속 3.2m/s'], ['조위', '중조 (TP +1.2m)'], ['파고', '0.5-1.0m'], ['수온', '14.2°C'], ].map(([k, v], i) => (
{k} {v}
))}
)} {popTab === 1 && (
{data.code} {data.name} — 조사 이력
{[ { date: '2026-01-15', team: '제주해경 방제과', type: 'Pre-SCAT', status: '완료', note: '초기 사전조사 실시. ESI 확인.' }, ].map((h, i) => (
{h.date} {h.type}
조사팀: {h.team}
{h.note}
))}
)}
) } export default ScatPopup