kcg-monitoring/frontend/src/hooks/useAuth.ts
htlee 2534faa488 feat: 프론트엔드 모노레포 이관 + signal-batch 연동 + Tailwind/i18n/테마 전환
- 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>
2026-03-17 13:54:41 +09:00

79 lines
1.7 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import {
googleLogin,
getMe,
logout as logoutApi,
} from '../services/authApi';
import type { AuthUser } from '../services/authApi';
interface AuthState {
user: AuthUser | null;
isLoading: boolean;
isAuthenticated: boolean;
}
const DEV_USER: AuthUser = {
email: 'dev@gcsc.co.kr',
name: 'Developer',
};
export function useAuth() {
const [state, setState] = useState<AuthState>({
user: null,
isLoading: true,
isAuthenticated: false,
});
useEffect(() => {
let cancelled = false;
getMe()
.then((user) => {
if (!cancelled) {
setState({ user, isLoading: false, isAuthenticated: true });
}
})
.catch(() => {
if (!cancelled) {
setState({ user: null, isLoading: false, isAuthenticated: false });
}
});
return () => {
cancelled = true;
};
}, []);
const login = useCallback(async (credential: string) => {
setState((prev) => ({ ...prev, isLoading: true }));
try {
const user = await googleLogin(credential);
setState({ user, isLoading: false, isAuthenticated: true });
} catch {
setState({ user: null, isLoading: false, isAuthenticated: false });
throw new Error('Login failed');
}
}, []);
const devLogin = useCallback(() => {
setState({ user: DEV_USER, isLoading: false, isAuthenticated: true });
}, []);
const logout = useCallback(async () => {
try {
await logoutApi();
} finally {
setState({ user: null, isLoading: false, isAuthenticated: false });
}
}, []);
return {
user: state.user,
isLoading: state.isLoading,
isAuthenticated: state.isAuthenticated,
login,
devLogin,
logout,
};
}