/* ============================================================
Root app — auth, hash-free state routing, role gating
============================================================ */
const { useState: useSR, useEffect: useER } = React;
function BootSplash() {
return (
LG AI 365
);
}
function loadRoute() {
try { const r = JSON.parse(localStorage.getItem('lg_route')); if (r && r.name) return r; } catch (e) {}
return { name: 'home' };
}
function AppInner() {
const toast = useToast();
const [user, setUser] = useSR(undefined); // undefined = checking
const [route, setRoute] = useSR(loadRoute());
useER(() => {
const t = localStorage.getItem('lg_token');
if (t) { window.api.setToken(t); window.api.me().then(setUser).catch(() => { setUser(null); }); }
else setUser(null);
}, []);
const navigate = (r) => { setRoute(r); localStorage.setItem('lg_route', JSON.stringify(r)); };
const onLogin = ({ token, user }) => { localStorage.setItem('lg_token', token); setUser(user); navigate({ name: 'home' }); };
const onLogout = () => { window.api.logout(); localStorage.removeItem('lg_token'); localStorage.removeItem('lg_route'); setUser(null); setRoute({ name: 'home' }); };
// Context project for the viewer. 프로세스·WBS is GLOBAL but still needs a project
// for context (project.id / periodStart), so always keep one: prefer the 운영가이드
// 표기(ON=active) project, else fall back to the first. The active check only gates
// the 콘텐츠 tab below — WBS/프로세스 must never depend on it.
const projQ = useAsync(() => (user ? window.api.getProjects().then((l) => l.find((p) => p.status === 'active') || l[0] || null) : Promise.resolve(null)), [user]);
const project = projQ.data;
if (user === undefined) return ;
if (!user) return ;
// role gate: LGE cannot reach admin screens
let r = route;
if (user.role === 'LGE' && (r.name === 'audit' || r.name === 'users' || r.name === 'eplog' || r.name === 'epadmin')) r = { name: 'home' };
if (user.role === 'LGE' && r.name === 'project' && r.tab === 'history') r = { ...r, tab: 'episodes' };
let content;
if (r.name === 'audit') content = ;
else if (r.name === 'eplog') content = ;
else if (r.name === 'epadmin') content = ;
else if (r.name === 'users') content = ;
else { // home/project → the single operation
if (projQ.loading) content = ;
else if (projQ.error) content =
;
else if (project) {
const m = r.month || (project.months[0] && project.months[0].month) || null;
const common = { project, month: m, user, navigate, toast };
// 콘텐츠 tab only shows when a project is 표기 ON(active); otherwise "운영 중인 가이드
// 없음". 프로세스·WBS (else) and history always render against the context project.
if (r.tab === 'episodes') content = project.status === 'active'
?
: } title="운영 중인 가이드가 없습니다" desc="운영가이드 표기(ON)된 운영 가이드가 없습니다." />
;
else if (r.tab === 'history') content = ;
else content = ;
} else content = } title="운영 중인 가이드가 없습니다" desc="운영가이드 표기(ON)된 운영 가이드가 없습니다." />
;
}
return (
{content}
);
}
function ProjectLoading() {
return (
);
}
function App() { return ; }
ReactDOM.createRoot(document.getElementById('root')).render();