kcg-monitoring/frontend/src/hooks/useGroupPolygons.ts
htlee 9cad89113d feat(frontend): FleetClusterLayer 서버사이드 폴리곤 전환
- vesselAnalysis.ts: GroupPolygonDto 타입 + fetchGroupPolygons/Detail/History
- useGroupPolygons.ts: 5분 폴링 훅 (fleetGroups/gearInZone/gearOutZone)
- FleetClusterLayer: 클라이언트 convexHull/padPolygon 제거 → API GeoJSON 렌더링
- KoreaDashboard/KoreaMap: groupPolygons 훅 연결 + props 전달
2026-03-24 13:42:14 +09:00

70 lines
1.9 KiB
TypeScript

import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { fetchGroupPolygons } from '../services/vesselAnalysis';
import type { GroupPolygonDto } from '../services/vesselAnalysis';
const POLL_INTERVAL_MS = 5 * 60_000; // 5분
export interface UseGroupPolygonsResult {
fleetGroups: GroupPolygonDto[];
gearInZoneGroups: GroupPolygonDto[];
gearOutZoneGroups: GroupPolygonDto[];
allGroups: GroupPolygonDto[];
isLoading: boolean;
lastUpdated: number;
}
const EMPTY: UseGroupPolygonsResult = {
fleetGroups: [],
gearInZoneGroups: [],
gearOutZoneGroups: [],
allGroups: [],
isLoading: false,
lastUpdated: 0,
};
export function useGroupPolygons(enabled: boolean): UseGroupPolygonsResult {
const [allGroups, setAllGroups] = useState<GroupPolygonDto[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [lastUpdated, setLastUpdated] = useState(0);
const timerRef = useRef<ReturnType<typeof setInterval>>();
const load = useCallback(async () => {
setIsLoading(true);
try {
const groups = await fetchGroupPolygons();
setAllGroups(groups);
setLastUpdated(Date.now());
} catch {
// 네트워크 오류 시 기존 데이터 유지
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
if (!enabled) return;
load();
timerRef.current = setInterval(load, POLL_INTERVAL_MS);
return () => clearInterval(timerRef.current);
}, [enabled, load]);
const fleetGroups = useMemo(
() => allGroups.filter(g => g.groupType === 'FLEET'),
[allGroups],
);
const gearInZoneGroups = useMemo(
() => allGroups.filter(g => g.groupType === 'GEAR_IN_ZONE'),
[allGroups],
);
const gearOutZoneGroups = useMemo(
() => allGroups.filter(g => g.groupType === 'GEAR_OUT_ZONE'),
[allGroups],
);
if (!enabled) return EMPTY;
return { fleetGroups, gearInZoneGroups, gearOutZoneGroups, allGroups, isLoading, lastUpdated };
}