159 lines
4.3 KiB
TypeScript
Executable File
159 lines
4.3 KiB
TypeScript
Executable File
import { useState, useEffect } from 'react';
|
|
import { Routes, Route } from 'react-router-dom';
|
|
import { GoogleOAuthProvider } from '@react-oauth/google';
|
|
import type { MainTab } from '@common/types/navigation';
|
|
import { MainLayout } from '@common/components/layout/MainLayout';
|
|
import { LoginPage } from '@common/components/auth/LoginPage';
|
|
import { registerMainTabSwitcher } from '@common/hooks/useSubMenu';
|
|
import { useAuthStore } from '@common/store/authStore';
|
|
import { useMenuStore } from '@common/store/menuStore';
|
|
import { useMapStore } from '@common/store/mapStore';
|
|
import { API_BASE_URL } from '@common/services/api';
|
|
import { OilSpillView } from '@tabs/prediction';
|
|
import { ReportsView } from '@tabs/reports';
|
|
import { HNSView } from '@tabs/hns';
|
|
import { AerialView } from '@tabs/aerial';
|
|
import { AssetsView } from '@tabs/assets';
|
|
import { BoardView } from '@tabs/board';
|
|
import { WeatherView } from '@tabs/weather';
|
|
import { IncidentsView } from '@tabs/incidents';
|
|
import { AdminView } from '@tabs/admin';
|
|
import { ScatView } from '@tabs/scat';
|
|
import { RescueView } from '@tabs/rescue';
|
|
import { DesignPage } from '@/pages/design/DesignPage';
|
|
|
|
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || '';
|
|
|
|
function App() {
|
|
const [activeMainTab, setActiveMainTab] = useState<MainTab>('prediction');
|
|
const { isAuthenticated, isLoading, checkSession } = useAuthStore();
|
|
const { loadMenuConfig } = useMenuStore();
|
|
const { loadMapTypes } = useMapStore();
|
|
|
|
useEffect(() => {
|
|
checkSession();
|
|
}, [checkSession]);
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated) {
|
|
loadMenuConfig();
|
|
loadMapTypes();
|
|
}
|
|
}, [isAuthenticated, loadMenuConfig, loadMapTypes]);
|
|
|
|
useEffect(() => {
|
|
registerMainTabSwitcher(setActiveMainTab);
|
|
}, []);
|
|
|
|
// 감사 로그: 탭 이동 기록
|
|
useEffect(() => {
|
|
if (!isAuthenticated) return;
|
|
const blob = new Blob([JSON.stringify({ action: 'TAB_VIEW', detail: activeMainTab })], {
|
|
type: 'text/plain',
|
|
});
|
|
navigator.sendBeacon(`${API_BASE_URL}/audit/log`, blob);
|
|
}, [activeMainTab, isAuthenticated]);
|
|
|
|
// 세션 확인 중 스플래시
|
|
if (isLoading) {
|
|
return (
|
|
<div
|
|
style={{
|
|
width: '100vw',
|
|
height: '100vh',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'var(--bg-base)',
|
|
gap: 16,
|
|
}}
|
|
>
|
|
<img
|
|
src="/wing_logo_text_white.svg"
|
|
alt="WING"
|
|
className="wing-logo"
|
|
style={{ height: 28, opacity: 0.8 }}
|
|
/>
|
|
<div
|
|
style={{
|
|
width: 32,
|
|
height: 32,
|
|
border: '3px solid rgba(6,182,212,0.2)',
|
|
borderTop: '3px solid rgba(6,182,212,0.8)',
|
|
borderRadius: '50%',
|
|
animation: 'loginSpin 0.8s linear infinite',
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// 미인증 → 로그인 페이지
|
|
if (!isAuthenticated) {
|
|
return <LoginPage />;
|
|
}
|
|
|
|
const renderView = () => {
|
|
switch (activeMainTab) {
|
|
case 'prediction':
|
|
return <OilSpillView />;
|
|
case 'reports':
|
|
return <ReportsView />;
|
|
case 'hns':
|
|
return <HNSView />;
|
|
case 'aerial':
|
|
return <AerialView />;
|
|
case 'assets':
|
|
return <AssetsView />;
|
|
case 'board':
|
|
return <BoardView />;
|
|
case 'weather':
|
|
return <WeatherView />;
|
|
case 'incidents':
|
|
return <IncidentsView />;
|
|
case 'scat':
|
|
return <ScatView />;
|
|
case 'admin':
|
|
return <AdminView />;
|
|
case 'rescue':
|
|
return <RescueView />;
|
|
case 'monitor':
|
|
return null;
|
|
default:
|
|
return (
|
|
<div className="flex items-center justify-center h-full text-fg-disabled">
|
|
준비 중입니다...
|
|
</div>
|
|
);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Routes>
|
|
<Route path="/design" element={<DesignPage />} />
|
|
<Route
|
|
path="*"
|
|
element={
|
|
<MainLayout activeMainTab={activeMainTab} onMainTabChange={setActiveMainTab}>
|
|
{renderView()}
|
|
</MainLayout>
|
|
}
|
|
/>
|
|
</Routes>
|
|
);
|
|
}
|
|
|
|
function AppWithProviders() {
|
|
if (!GOOGLE_CLIENT_ID) {
|
|
return <App />;
|
|
}
|
|
return (
|
|
<GoogleOAuthProvider clientId={GOOGLE_CLIENT_ID}>
|
|
<App />
|
|
</GoogleOAuthProvider>
|
|
);
|
|
}
|
|
|
|
export default AppWithProviders;
|