feat: React 프론트엔드 기능 대폭 확장

- 월별근무표: 휴일/근무일 관리, 자동 초기화
- 메일양식: 템플릿 CRUD, To/CC/BCC 설정
- 그룹정보: 부서 관리, 비트 연산 기반 권한 설정
- 업무일지: 수정 성공 메시지 제거, 오늘 근무시간 필터링 수정
- 웹소켓 메시지 type 충돌 버그 수정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-11-27 17:25:31 +09:00
parent b57af6dad7
commit c9b5d756e1
65 changed files with 14028 additions and 467 deletions

View File

@@ -0,0 +1,99 @@
import { useState, useEffect } from 'react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import { Layout } from '@/components/layout';
import { Dashboard, Todo, Kuntae, Jobreport, PlaceholderPage, Login, CommonCodePage, ItemsPage, UserListPage, MonthlyWorkPage, MailFormPage, UserGroupPage } from '@/pages';
import { comms } from '@/communication';
import { UserInfo } from '@/types';
import { Loader2 } from 'lucide-react';
export default function App() {
const [isConnected, setIsConnected] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState<boolean | null>(null); // null = 체크 중
const [user, setUser] = useState<UserInfo | null>(null);
useEffect(() => {
// 통신 상태 구독
const unsubscribe = comms.subscribe((msg: unknown) => {
const message = msg as { type?: string; connected?: boolean };
if (message?.type === 'CONNECTION_STATE') {
setIsConnected(message.connected ?? false);
// 연결되면 로그인 상태 체크
if (message.connected) {
checkLoginStatus();
}
}
});
// 초기 연결 상태 설정
setIsConnected(comms.getConnectionState());
// 연결되어 있으면 바로 로그인 상태 체크
if (comms.getConnectionState()) {
checkLoginStatus();
}
return () => {
unsubscribe();
};
}, []);
const checkLoginStatus = async () => {
try {
const result = await comms.checkLoginStatus();
if (result.Success) {
setIsLoggedIn(result.IsLoggedIn);
setUser(result.User);
} else {
setIsLoggedIn(false);
setUser(null);
}
} catch (err) {
console.error('로그인 상태 체크 실패:', err);
setIsLoggedIn(false);
setUser(null);
}
};
const handleLoginSuccess = () => {
checkLoginStatus();
};
// 로그인 상태 체크 중
if (isLoggedIn === null) {
return (
<div className="min-h-screen bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 flex items-center justify-center">
<div className="text-center">
<Loader2 className="w-10 h-10 text-white animate-spin mx-auto mb-4" />
<p className="text-white/70"> ...</p>
</div>
</div>
);
}
// 로그인 안됨 → 로그인 화면 표시
if (!isLoggedIn) {
return <Login onLoginSuccess={handleLoginSuccess} />;
}
// 로그인 됨 → 메인 앱 표시
return (
<HashRouter>
<Routes>
<Route element={<Layout isConnected={isConnected} user={user} />}>
<Route path="/" element={<Dashboard />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/todo" element={<Todo />} />
<Route path="/kuntae" element={<Kuntae />} />
<Route path="/jobreport" element={<Jobreport />} />
<Route path="/project" element={<PlaceholderPage title="프로젝트" />} />
<Route path="/common" element={<CommonCodePage />} />
<Route path="/items" element={<ItemsPage />} />
<Route path="/user/list" element={<UserListPage />} />
<Route path="/monthly-work" element={<MonthlyWorkPage />} />
<Route path="/mail-form" element={<MailFormPage />} />
<Route path="/user-group" element={<UserGroupPage />} />
</Route>
</Routes>
</HashRouter>
);
}