wing-ops/frontend/src/tabs/weather/hooks/useOceanForecast.ts
leedano 3743027ce7 feat(weather): 기상 정보 기상 레이어 업데이트 (#78)
## Summary
- 기상 맵 컨트롤 컴포넌트 추가 및 KHOA API 연동 개선
- KHOA API 엔드포인트 교체 및 해양예측 오버레이 Canvas 렌더링 전환

## 변경 파일
- OceanForecastOverlay.tsx
- WeatherMapOverlay.tsx
- WeatherView.tsx
- useOceanForecast.ts
- khoaApi.ts
- vite.config.ts

## Test plan
- [ ] 기상정보 -> 기상 레이어 -> 해황 예보도 클릭 -> 이미지 렌더링 확인
- [ ] 기상정보 -> 기상 레이어 -> 백터 바람 클릭 -> 백터 이미지 렌더링 확인

Co-authored-by: Nan Kyung Lee <nankyunglee@Nanui-Macmini.local>
Reviewed-on: #78
Co-authored-by: leedano <dnlee@gcsc.co.kr>
Co-committed-by: leedano <dnlee@gcsc.co.kr>
2026-03-11 11:14:25 +09:00

114 lines
3.1 KiB
TypeScript
Executable File

import { useState, useEffect } from 'react'
import {
getOceanForecast,
getLatestForecast,
getForecastByTime,
type OceanForecastData
} from '../services/khoaApi'
interface UseOceanForecastReturn {
forecasts: OceanForecastData[]
latestForecast: OceanForecastData | null
selectedForecast: OceanForecastData | null
loading: boolean
error: string | null
lastUpdate: Date | null
refetch: () => Promise<void>
selectForecast: (day: string, hour: string) => void
availableTimes: Array<{ day: string; hour: string; label: string }>
}
/**
* 해황예보도 데이터 가져오기 훅
* @param regionType 지역 유형 (KOREA, INCHEON 등)
* @param autoRefresh 자동 갱신 여부 (기본: true, 30분마다)
*/
export function useOceanForecast(
regionType: string = 'KOREA',
autoRefresh: boolean = true
): UseOceanForecastReturn {
const [forecasts, setForecasts] = useState<OceanForecastData[]>([])
const [latestForecast, setLatestForecast] = useState<OceanForecastData | null>(null)
const [selectedForecast, setSelectedForecast] = useState<OceanForecastData | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [lastUpdate, setLastUpdate] = useState<Date | null>(null)
const fetchForecastData = async () => {
try {
setLoading(true)
setError(null)
const data = await getOceanForecast(regionType)
setForecasts(data)
const latest = getLatestForecast(data)
setLatestForecast(latest)
// 선택된 예보가 없으면 최신 예보를 선택
if (!selectedForecast && latest) {
setSelectedForecast(latest)
}
setLastUpdate(new Date())
} catch (err) {
console.error('해황예보도 데이터 가져오기 오류:', err)
setError(err instanceof Error ? err.message : '알 수 없는 오류')
} finally {
setLoading(false)
}
}
// 특정 시간대의 예보 선택
const selectForecast = (day: string, hour: string) => {
const forecast = getForecastByTime(forecasts, day, hour)
if (forecast) {
setSelectedForecast(forecast)
}
}
// 사용 가능한 시간대 목록 생성
const availableTimes = forecasts
.map((f) => ({
day: f.ofcFrcstYmd,
hour: f.ofcFrcstTm,
label: `${f.ofcFrcstYmd.slice(4, 6)}/${f.ofcFrcstYmd.slice(6, 8)} ${f.ofcFrcstTm}:00`
}))
.sort((a, b) => `${a.day}${a.hour}`.localeCompare(`${b.day}${b.hour}`))
useEffect(() => {
let isMounted = true
let interval: NodeJS.Timeout | null = null
const loadData = async () => {
if (isMounted) {
await fetchForecastData()
}
}
loadData()
// 자동 갱신 설정 (30분마다)
if (autoRefresh) {
interval = setInterval(loadData, 30 * 60 * 1000)
}
return () => {
isMounted = false
if (interval) clearInterval(interval)
}
}, [regionType, autoRefresh])
return {
forecasts,
latestForecast,
selectedForecast,
loading,
error,
lastUpdate,
refetch: fetchForecastData,
selectForecast,
availableTimes
}
}