293 lines
11 KiB
JavaScript
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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|