feat(frontend): 공통 UI 로더 및 대시보드 구조 개선
- auth-check, load-navbar, load-sidebar 리팩토링 - auth.js 모듈을 활용하여 코드 중복 제거 및 일관성 확보 - DOMParser를 사용하여 컴포넌트 로딩 시 화면 깜빡임 현상 해결 - user-dashboard에 API 연동을 위한 견고한 기반 코드 마련
This commit is contained in:
@@ -1,46 +1,67 @@
|
||||
// ✅ /js/load-sidebar.js (access_level 기반 메뉴 필터링)
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
try {
|
||||
// 1) 사이드바 HTML 로딩
|
||||
const res = await fetch('/components/sidebar.html');
|
||||
const html = await res.text();
|
||||
document.getElementById('sidebar-container').innerHTML = html;
|
||||
// /js/load-sidebar.js
|
||||
import { getUser } from './auth.js';
|
||||
|
||||
// 2) 토큰 존재 확인
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) return;
|
||||
/**
|
||||
* 사용자 역할에 따라 사이드바 메뉴 항목을 필터링합니다.
|
||||
* @param {Document} doc - 파싱된 HTML 문서 객체
|
||||
* @param {string} userRole - 현재 사용자의 역할
|
||||
*/
|
||||
function filterSidebarByRole(doc, userRole) {
|
||||
// 'system' 역할은 모든 메뉴를 볼 수 있으므로 필터링하지 않음
|
||||
if (userRole === 'system') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 역할과 그에 해당하는 클래스 선택자 매핑
|
||||
const roleClassMap = {
|
||||
admin: '.admin-only',
|
||||
leader: '.leader-only',
|
||||
user: '.user-only', // 또는 'worker-only' 등, sidebar.html에 정의된 클래스에 맞춰야 함
|
||||
support: '.support-only'
|
||||
};
|
||||
|
||||
// 3) JWT 파싱해서 access_level 추출
|
||||
let access;
|
||||
try {
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
access = payload.access_level;
|
||||
} catch (err) {
|
||||
console.warn('JWT 파싱 실패:', err);
|
||||
return;
|
||||
// 모든 역할 기반 선택자를 가져옴
|
||||
const allRoleSelectors = Object.values(roleClassMap).join(', ');
|
||||
const allRoleElements = doc.querySelectorAll(allRoleSelectors);
|
||||
|
||||
allRoleElements.forEach(el => {
|
||||
// 요소가 현재 사용자 역할에 해당하는 클래스를 가지고 있는지 확인
|
||||
const userRoleSelector = roleClassMap[userRole];
|
||||
if (!userRoleSelector || !el.matches(userRoleSelector)) {
|
||||
el.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4) 시스템 계정은 전부 유지
|
||||
if (access === 'system') return;
|
||||
|
||||
// 5) 클래스 이름 목록
|
||||
const classMap = [
|
||||
'worker-only',
|
||||
'group-leader-only',
|
||||
'support-only',
|
||||
'admin-only',
|
||||
'system-only'
|
||||
];
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const sidebarContainer = document.getElementById('sidebar-container');
|
||||
if (!sidebarContainer) return;
|
||||
|
||||
// 6) 본인 권한에 해당하지 않는 요소 제거
|
||||
classMap.forEach(cls => {
|
||||
const required = cls.replace('-only', '').replace('-', '_'); // 'group-leader-only' → 'group_leader'
|
||||
if (access !== required) {
|
||||
document.querySelectorAll(`.${cls}`).forEach(el => el.remove());
|
||||
}
|
||||
});
|
||||
const currentUser = getUser();
|
||||
if (!currentUser) return; // 비로그인 상태면 사이드바를 로드하지 않음
|
||||
|
||||
} catch (err) {
|
||||
console.error('🔴 사이드바 로딩 실패:', err);
|
||||
try {
|
||||
const response = await fetch('/components/sidebar.html');
|
||||
if (!response.ok) {
|
||||
throw new Error(`사이드바 파일을 불러올 수 없습니다: ${response.statusText}`);
|
||||
}
|
||||
const htmlText = await response.text();
|
||||
|
||||
// 1. 텍스트를 가상 DOM으로 파싱
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(htmlText, 'text/html');
|
||||
|
||||
// 2. DOM에 삽입하기 *전*에 역할에 따라 메뉴 필터링
|
||||
filterSidebarByRole(doc, currentUser.role);
|
||||
|
||||
// 3. 수정 완료된 HTML을 실제 DOM에 삽입
|
||||
sidebarContainer.innerHTML = doc.body.innerHTML;
|
||||
|
||||
console.log('✅ 사이드바 로딩 및 필터링 완료');
|
||||
|
||||
} catch (error) {
|
||||
console.error('🔴 사이드바 로딩 실패:', error);
|
||||
sidebarContainer.innerHTML = '<p>메뉴 로딩 실패</p>';
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user