import React, { useState, useEffect } from 'react'; import SimpleLogin from './SimpleLogin'; import BOMWorkspacePage from './pages/BOMWorkspacePage'; import NewMaterialsPage from './pages/NewMaterialsPage'; import SystemSettingsPage from './pages/SystemSettingsPage'; import AccountSettingsPage from './pages/AccountSettingsPage'; import UserManagementPage from './pages/UserManagementPage'; import SystemLogsPage from './pages/SystemLogsPage'; import LogMonitoringPage from './pages/LogMonitoringPage'; import ErrorBoundary from './components/ErrorBoundary'; import errorLogger from './utils/errorLogger'; import api from './api'; import './App.css'; function App() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [isLoading, setIsLoading] = useState(true); const [user, setUser] = useState(null); const [currentPage, setCurrentPage] = useState('dashboard'); const [pageParams, setPageParams] = useState({}); const [selectedProject, setSelectedProject] = useState(null); const [showUserMenu, setShowUserMenu] = useState(false); const [projects, setProjects] = useState([]); const [editingProject, setEditingProject] = useState(null); const [editedProjectName, setEditedProjectName] = useState(''); const [showCreateProject, setShowCreateProject] = useState(false); const [newProjectCode, setNewProjectCode] = useState(''); const [newProjectName, setNewProjectName] = useState(''); const [newClientName, setNewClientName] = useState(''); const [pendingSignupCount, setPendingSignupCount] = useState(0); // 승인 대기 중인 회원가입 수 조회 const loadPendingSignups = async () => { try { const response = await api.get('/auth/signup-requests'); if (response.data && response.data.requests) { setPendingSignupCount(response.data.count || 0); } } catch (error) { // 에러 무시 (관리자가 아니면 403) } }; // 프로젝트 목록 로드 const loadProjects = async () => { try { const response = await api.get('/dashboard/projects'); if (response.data && response.data.projects) { setProjects(response.data.projects); } } catch (error) { console.error('프로젝트 목록 로드 실패:', error); // API 실패 시 에러를 무시하고 더미 데이터 사용 } }; // 프로젝트 생성 const createProject = async () => { if (!newProjectCode || !newProjectName) { alert('프로젝트 코드와 이름을 입력해주세요.'); return; } try { const response = await api.post(`/dashboard/projects?official_project_code=${encodeURIComponent(newProjectCode)}&project_name=${encodeURIComponent(newProjectName)}&client_name=${encodeURIComponent(newClientName)}`); if (response.data.success) { // 프로젝트 목록 갱신 await loadProjects(); // 폼 초기화 setShowCreateProject(false); setNewProjectCode(''); setNewProjectName(''); setNewClientName(''); alert('프로젝트가 생성되었습니다.'); } } catch (error) { console.error('프로젝트 생성 실패:', error); const errorMsg = error.response?.data?.detail || '프로젝트 생성에 실패했습니다.'; alert(errorMsg); } }; // 프로젝트 이름 수정 const updateProjectName = async (projectId) => { try { const response = await api.patch(`/dashboard/projects/${projectId}?job_name=${encodeURIComponent(editedProjectName)}`); if (response.data.success) { // 프로젝트 목록 갱신 await loadProjects(); // 선택된 프로젝트 업데이트 if (selectedProject && selectedProject.id === projectId) { setSelectedProject({ ...selectedProject, project_name: editedProjectName }); } setEditingProject(null); setEditedProjectName(''); alert('프로젝트 이름이 수정되었습니다.'); } } catch (error) { console.error('프로젝트 이름 수정 실패:', error); alert('프로젝트 이름 수정에 실패했습니다.'); } }; useEffect(() => { // 저장된 토큰 확인 const token = localStorage.getItem('access_token'); const userData = localStorage.getItem('user_data'); if (token && userData) { setIsAuthenticated(true); const userObj = JSON.parse(userData); setUser(userObj); loadProjects(); // 프로젝트 목록 로드 // 관리자인 경우 승인 대기 수 조회 if (userObj.role === 'admin' || userObj.role === 'system') { loadPendingSignups(); // 30초마다 갱신 const interval = setInterval(loadPendingSignups, 30000); return () => clearInterval(interval); } } setIsLoading(false); // 자재 목록 페이지로 이동 이벤트 리스너 const handleNavigateToMaterials = (event) => { const { jobNo, revision, bomName, message, file_id } = event.detail; navigateToPage('materials', { jobNo: jobNo, revision: revision, bomName: bomName, message: message, file_id: file_id // file_id 추가 }); }; window.addEventListener('navigateToMaterials', handleNavigateToMaterials); return () => { window.removeEventListener('navigateToMaterials', handleNavigateToMaterials); }; }, []); // 사용자 메뉴 외부 클릭 시 닫기 useEffect(() => { const handleClickOutside = (event) => { if (showUserMenu && !event.target.closest('.user-menu-container')) { setShowUserMenu(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [showUserMenu]); // 로그인 성공 시 호출될 함수 const handleLoginSuccess = () => { const userData = localStorage.getItem('user_data'); if (userData) { setUser(JSON.parse(userData)); } setIsAuthenticated(true); }; // 로그아웃 함수 const handleLogout = () => { localStorage.removeItem('access_token'); localStorage.removeItem('user_data'); setIsAuthenticated(false); setUser(null); setCurrentPage('dashboard'); }; // 페이지 네비게이션 함수 const navigateToPage = (page, params = {}) => { setCurrentPage(page); setPageParams(params); }; // 핵심 기능만 제공 const getCoreFeatures = () => { return [ { id: 'bom', title: '📋 BOM 업로드 & 분류', description: '엑셀 파일 업로드 → 자동 분류 → 검토 → 자재 확인 → 엑셀 내보내기', color: '#4299e1' } ]; }; // 관리자 전용 기능 const getAdminFeatures = () => { const features = []; // 시스템 관리자 전용 기능 if (user?.role === 'system') { features.push( { id: 'user-management', title: '👥 사용자 관리', description: '계정 생성, 역할 변경, 사용자 삭제', color: '#dc2626', badge: '시스템 관리자' }, { id: 'system-logs', title: '📊 시스템 로그', description: '로그인 기록, 시스템 오류 로그 조회', color: '#7c3aed', badge: '시스템 관리자' } ); } // 관리자 이상 공통 기능 if (user?.role === 'admin' || user?.role === 'system') { features.push( { id: 'log-monitoring', title: '📈 로그 모니터링', description: '사용자 활동 로그 및 오류 모니터링', color: '#059669', badge: user?.role === 'system' ? '시스템 관리자' : '관리자' } ); } return features; }; // 페이지 렌더링 함수 const renderCurrentPage = () => { console.log('현재 페이지:', currentPage, '페이지 파라미터:', pageParams); switch (currentPage) { case 'dashboard': const coreFeatures = getCoreFeatures(); const adminFeatures = getAdminFeatures(); return (
{/* 상단 헤더 */}

🏭 TK-MP BOM 관리 시스템

{user?.name || user?.username}님 환영합니다

{/* 알람 및 사용자 메뉴 */}
{/* 회원가입 승인 알람 (관리자 전용) */} {(user?.role === 'admin' || user?.role === 'system') && pendingSignupCount > 0 && ( )} {/* 사용자 메뉴 */}
{/* 드롭다운 메뉴 */} {showUserMenu && (
{user?.name || user?.username}
{user?.email || '이메일 없음'}
)}
{/* 메인 콘텐츠 */}
{/* 프로젝트 관리 */}

📁 프로젝트 관리

{selectedProject && ( )}
{/* 프로젝트 생성 폼 */} {showCreateProject && (
➕ 새 프로젝트 생성
setNewProjectCode(e.target.value)} placeholder="예: J24-004" style={{ width: '100%', padding: '10px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />
setNewProjectName(e.target.value)} placeholder="예: 새로운 프로젝트" style={{ width: '100%', padding: '10px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />
setNewClientName(e.target.value)} placeholder="예: ABC 주식회사" style={{ width: '100%', padding: '10px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />
)} {/* 프로젝트 이름 편집 폼 */} {editingProject && (
프로젝트 이름 수정: {editingProject.official_project_code}
setEditedProjectName(e.target.value)} onKeyPress={(e) => { if (e.key === 'Enter') updateProjectName(editingProject.id); }} placeholder="새 프로젝트 이름" autoFocus style={{ flex: 1, padding: '10px 12px', border: '2px solid #3b82f6', borderRadius: '6px', fontSize: '14px' }} />
)}
{/* 핵심 기능 */} {selectedProject && ( <>

📋 BOM 관리 워크플로우

{coreFeatures.map((feature) => (
{ e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 8px 12px rgba(0, 0, 0, 0.1)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.07)'; }} >

{feature.title}

{feature.description}

))}
{/* 관리자 기능 (있는 경우만) */} {adminFeatures.length > 0 && (

⚙️ 시스템 관리

{adminFeatures.map((feature) => (
{ e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 8px 12px rgba(0, 0, 0, 0.1)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.07)'; }} >

{feature.title}

{feature.description}

{feature.badge} 전용
))}
)} {/* 간단한 사용법 안내 */}

📖 간단한 사용법

1 BOM 업로드
2 자동 분류
3 엑셀 내보내기
)} {/* selectedProject 조건문 닫기 */}
); case 'bom': return ( navigateToPage('dashboard')} /> ); case 'materials': return ( ); case 'system-settings': return ( ); case 'account-settings': return ( { setUser(updatedUser); localStorage.setItem('user_data', JSON.stringify(updatedUser)); }} /> ); case 'user-management': return ( ); case 'system-logs': return ( ); case 'log-monitoring': return ( ); default: return (

페이지를 찾을 수 없습니다

); } }; // 로딩 중 if (isLoading) { return (
🔄
로딩 중...
); } // 로그인하지 않은 경우 if (!isAuthenticated) { return ; } // 메인 애플리케이션 return (
{renderCurrentPage()}
); } export default App;