Files
tk-factory-services/tkeg/web/src/components/NavigationBar.jsx
2026-03-16 15:41:58 +09:00

293 lines
11 KiB
JavaScript

import React, { useState } from 'react';
import { useAuth } from '../contexts/AuthContext';
import './NavigationBar.css';
const NavigationBar = ({ currentPage, onNavigate }) => {
const { user, logout, hasPermission, isAdmin, isManager } = useAuth();
const [showUserMenu, setShowUserMenu] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// 메뉴 항목 정의 (권한별)
const menuItems = [
{
id: 'dashboard',
label: '대시보드',
icon: '📊',
path: '/dashboard',
permission: null, // 모든 사용자 접근 가능
description: '전체 현황 보기'
},
{
id: 'projects',
label: '프로젝트 관리',
icon: '📋',
path: '/projects',
permission: 'project.view',
description: '프로젝트 등록 및 관리'
},
{
id: 'bom',
label: 'BOM 관리',
icon: '📄',
path: '/bom',
permission: 'bom.view',
description: 'BOM 파일 업로드 및 분석'
},
{
id: 'materials',
label: '자재 관리',
icon: '🔧',
path: '/materials',
permission: 'bom.view',
description: '자재 목록 및 비교'
},
{
id: 'purchase',
label: '구매 관리',
icon: '💰',
path: '/purchase',
permission: 'project.view',
description: '구매 확인 및 관리'
},
{
id: 'files',
label: '파일 관리',
icon: '📁',
path: '/files',
permission: 'file.upload',
description: '파일 업로드 및 관리'
},
{
id: 'users',
label: '사용자 관리',
icon: '👥',
path: '/users',
permission: 'user.view',
description: '사용자 계정 관리',
adminOnly: true
},
{
id: 'system',
label: '시스템 설정',
icon: '⚙️',
path: '/system',
permission: 'system.admin',
description: '시스템 환경 설정',
adminOnly: true
}
];
// 사용자가 접근 가능한 메뉴만 필터링
const accessibleMenuItems = menuItems.filter(item => {
// 관리자 전용 메뉴 체크
if (item.adminOnly && !isAdmin() && !isManager()) {
return false;
}
// 권한 체크
if (item.permission && !hasPermission(item.permission)) {
return false;
}
return true;
});
const handleLogout = async () => {
try {
await logout();
setShowUserMenu(false);
} catch (error) {
console.error('Logout failed:', error);
}
};
const handleMenuClick = (item) => {
onNavigate(item.id);
setIsMobileMenuOpen(false);
};
const getRoleDisplayName = (role) => {
const roleMap = {
'admin': '관리자',
'system': '시스템',
'leader': '팀장',
'support': '지원',
'user': '사용자'
};
return roleMap[role] || role;
};
const getAccessLevelDisplayName = (level) => {
const levelMap = {
'manager': '관리자',
'leader': '팀장',
'worker': '작업자',
'viewer': '조회자'
};
return levelMap[level] || level;
};
return (
<nav className="navigation-bar">
<div className="nav-container">
{/* 로고 및 브랜드 */}
<div className="nav-brand">
<div className="brand-logo">🚀</div>
<div className="brand-text">
<h1>TK-MP System</h1>
<span>통합 프로젝트 관리</span>
</div>
</div>
{/* 모바일 메뉴 토글 */}
<button
className="mobile-menu-toggle"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
<span></span>
<span></span>
<span></span>
</button>
{/* 메인 메뉴 */}
<div className={`nav-menu ${isMobileMenuOpen ? 'mobile-open' : ''}`}>
<div className="menu-items">
{accessibleMenuItems.map(item => (
<button
key={item.id}
className={`menu-item ${currentPage === item.id ? 'active' : ''}`}
onClick={() => handleMenuClick(item)}
title={item.description}
>
<span className="menu-icon">{item.icon}</span>
<span className="menu-label">{item.label}</span>
{item.adminOnly && (
<span className="admin-badge">관리자</span>
)}
</button>
))}
</div>
{/* 사용자 메뉴 */}
<div className="user-menu-container">
<button
className="user-menu-trigger"
onClick={() => setShowUserMenu(!showUserMenu)}
>
<div className="user-avatar">
{user?.name?.charAt(0) || '👤'}
</div>
<div className="user-info">
<span className="user-name">{user?.name}</span>
<span className="user-role">
{getRoleDisplayName(user?.role)} · {getAccessLevelDisplayName(user?.access_level)}
</span>
</div>
<span className="dropdown-arrow"></span>
</button>
{showUserMenu && (
<div className="user-dropdown">
<div className="user-dropdown-header">
<div className="user-avatar-large">
{user?.name?.charAt(0) || '👤'}
</div>
<div className="user-details">
<div className="user-name">{user?.name}</div>
<div className="user-username">@{user?.username}</div>
<div className="user-email">{user?.email}</div>
<div className="user-meta">
<span className="role-badge role-{user?.role}">
{getRoleDisplayName(user?.role)}
</span>
<span className="access-badge access-{user?.access_level}">
{getAccessLevelDisplayName(user?.access_level)}
</span>
</div>
{user?.department && (
<div className="user-department">{user.department}</div>
)}
</div>
</div>
<div className="user-dropdown-menu">
<button className="dropdown-item">
<span className="item-icon">👤</span>
프로필 설정
</button>
<button className="dropdown-item">
<span className="item-icon">🔐</span>
비밀번호 변경
</button>
<button className="dropdown-item">
<span className="item-icon">🔔</span>
알림 설정
</button>
<div className="dropdown-divider"></div>
<button
className="dropdown-item logout-item"
onClick={handleLogout}
>
<span className="item-icon">🚪</span>
로그아웃
</button>
</div>
<div className="user-dropdown-footer">
<div className="permissions-info">
<span className="permissions-label">권한:</span>
<div className="permissions-list">
{user?.permissions?.slice(0, 3).map(permission => (
<span key={permission} className="permission-tag">
{permission}
</span>
))}
{user?.permissions?.length > 3 && (
<span className="permission-more">
+{user.permissions.length - 3}
</span>
)}
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* 모바일 오버레이 */}
{isMobileMenuOpen && (
<div
className="mobile-overlay"
onClick={() => setIsMobileMenuOpen(false)}
/>
)}
</nav>
);
};
export default NavigationBar;