- vesselAnalysis.ts: GroupPolygonDto 타입 + fetchGroupPolygons/Detail/History - useGroupPolygons.ts: 5분 폴링 훅 (fleetGroups/gearInZone/gearOutZone) - FleetClusterLayer: 클라이언트 convexHull/padPolygon 제거 → API GeoJSON 렌더링 - KoreaDashboard/KoreaMap: groupPolygons 훅 연결 + props 전달
70 lines
1.9 KiB
TypeScript
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 };
|
|
}
|