- frontend/ 폴더로 프론트엔드 전체 이관 - signal-batch API 연동 (한국 선박 위치 데이터) - Tailwind CSS 4 + CSS 변수 테마 토큰 (dark/light) - i18next 다국어 (ko/en) 인프라 + 28개 컴포넌트 적용 - 레이어 패널 트리 구조 재설계 (카테고리별 온/오프, 범례) - Google OAuth 로그인 화면 + DEV LOGIN 우회 - 외부 API CORS 프록시 전환 (Airplanes.live, OpenSky, CelesTrak) - ShipLayer 이미지 탭 전환 (signal-batch / MarineTraffic) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
37 lines
1.1 KiB
TypeScript
37 lines
1.1 KiB
TypeScript
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
|
|
const TICK_INTERVAL = 1000; // update every 1 second in live mode
|
|
|
|
export interface MonitorState {
|
|
currentTime: number; // always Date.now()
|
|
historyMinutes: number; // how far back to show (default 60)
|
|
}
|
|
|
|
export function useMonitor() {
|
|
const [state, setState] = useState<MonitorState>({
|
|
currentTime: Date.now(),
|
|
historyMinutes: 60,
|
|
});
|
|
|
|
const intervalRef = useRef<number | null>(null);
|
|
|
|
// Start ticking immediately
|
|
useEffect(() => {
|
|
intervalRef.current = window.setInterval(() => {
|
|
setState(prev => ({ ...prev, currentTime: Date.now() }));
|
|
}, TICK_INTERVAL);
|
|
return () => {
|
|
if (intervalRef.current !== null) clearInterval(intervalRef.current);
|
|
};
|
|
}, []);
|
|
|
|
const setHistoryMinutes = useCallback((minutes: number) => {
|
|
setState(prev => ({ ...prev, historyMinutes: minutes }));
|
|
}, []);
|
|
|
|
const startTime = state.currentTime - state.historyMinutes * 60_000;
|
|
const endTime = state.currentTime;
|
|
|
|
return { state, startTime, endTime, setHistoryMinutes };
|
|
}
|