feat(web-ui): Refactor web-ui for improved maintainability and modularity
This commit introduces a series of refactoring changes to the web-ui to remove hardcoded values and improve page integration. - **Centralized Configuration:** Created to centralize API ports, paths, and navigation URLs, replacing hardcoded values across multiple files. - **Modular Component Loading:** Introduced to handle dynamic loading of common HTML components (e.g., sidebar, navbar), using paths from . - **Modular Navigation:** Created to centralize page redirection logic, improving maintainability and reducing direct manipulations. - **Refactored Existing Modules:** Updated , , , and to utilize the new , , and modules. - **ES6 Module Compatibility:** Ensured loads scripts as ES6 modules () to support statements.
This commit is contained in:
@@ -22,8 +22,8 @@
|
||||
</div>
|
||||
|
||||
<!-- 스크립트 로딩 (순서 중요) -->
|
||||
<script src="js/api-config.js"></script>
|
||||
<script src="js/api-helper.js"></script>
|
||||
<script src="js/login.js"></script>
|
||||
<script type="module" src="js/api-config.js"></script>
|
||||
<script type="module" src="js/api-helper.js"></script>
|
||||
<script type="module" src="js/login.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,6 @@
|
||||
// api-config.js - nginx 프록시 대응 API 설정
|
||||
import { config } from './config.js';
|
||||
import { redirectToLogin } from './navigation.js';
|
||||
|
||||
function getApiBaseUrl() {
|
||||
const hostname = window.location.hostname;
|
||||
@@ -13,8 +15,8 @@ function getApiBaseUrl() {
|
||||
hostname === 'localhost' || hostname === '127.0.0.1' ||
|
||||
hostname.includes('.local') || hostname.includes('hyungi')) {
|
||||
|
||||
// 현재 웹서버의 도메인/IP를 그대로 사용하되 API 포트(20005)로 직접 연결
|
||||
const baseUrl = `${protocol}//${hostname}:20005/api`;
|
||||
// 현재 웹서버의 도메인/IP를 그대로 사용하되 API 포트(config.api.port)로 직접 연결
|
||||
const baseUrl = `${protocol}//${hostname}:${config.api.port}${config.api.path}`;
|
||||
|
||||
console.log('✅ nginx 프록시 사용:', baseUrl);
|
||||
return baseUrl;
|
||||
@@ -22,7 +24,7 @@ function getApiBaseUrl() {
|
||||
|
||||
// 🚨 백업: 직접 접근 (nginx 프록시 실패시에만)
|
||||
console.warn('⚠️ 직접 API 접근 (백업 모드)');
|
||||
return `${protocol}//${hostname}:20005/api`;
|
||||
return `${protocol}//${hostname}:${config.api.port}${config.api.path}`;
|
||||
}
|
||||
|
||||
// API 설정
|
||||
@@ -37,7 +39,7 @@ function ensureAuthenticated() {
|
||||
if (!token || token === 'undefined' || token === 'null') {
|
||||
console.log('🚨 인증되지 않은 사용자. 로그인 페이지로 이동합니다.');
|
||||
clearAuthData(); // 만약을 위해 한번 더 정리
|
||||
window.location.href = '/index.html';
|
||||
redirectToLogin();
|
||||
return false; // 이후 코드 실행 방지
|
||||
}
|
||||
|
||||
@@ -46,7 +48,7 @@ function ensureAuthenticated() {
|
||||
console.log('🚨 토큰이 만료되었습니다. 로그인 페이지로 이동합니다.');
|
||||
clearAuthData();
|
||||
alert('세션이 만료되었습니다. 다시 로그인해주세요.');
|
||||
window.location.href = '/index.html';
|
||||
redirectToLogin();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -108,7 +110,7 @@ async function apiCall(url, method = 'GET', data = null) {
|
||||
console.error('🚨 인증 실패: 토큰이 만료되었거나 유효하지 않습니다.');
|
||||
clearAuthData();
|
||||
alert('세션이 만료되었습니다. 다시 로그인해주세요.');
|
||||
window.location.href = '/index.html';
|
||||
redirectToLogin();
|
||||
throw new Error('인증에 실패했습니다.');
|
||||
}
|
||||
|
||||
@@ -193,6 +195,6 @@ setInterval(() => {
|
||||
console.log('🚨 주기적 확인: 토큰이 만료되었습니다.');
|
||||
clearAuthData();
|
||||
alert('세션이 만료되었습니다. 다시 로그인해주세요.');
|
||||
window.location.href = '/index.html';
|
||||
redirectToLogin();
|
||||
}
|
||||
}, 5 * 60 * 1000); // 5분마다 확인
|
||||
}, config.app.tokenRefreshInterval); // 5분마다 확인
|
||||
53
web-ui/js/component-loader.js
Normal file
53
web-ui/js/component-loader.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// /js/component-loader.js
|
||||
import { config } from './config.js';
|
||||
|
||||
/**
|
||||
* 공용 HTML 컴포넌트를 페이지의 특정 위치에 동적으로 로드합니다.
|
||||
* @param {string} componentName - 로드할 컴포넌트의 이름 (e.g., 'sidebar', 'navbar'). config.js의 components 객체에 정의된 키와 일치해야 합니다.
|
||||
* @param {string} containerSelector - 컴포넌트가 삽입될 DOM 요소의 CSS 선택자 (e.g., '#sidebar-container').
|
||||
* @param {function(Document): void} [domProcessor=null] - DOM에 삽입하기 전에 로드된 HTML(Document)을 조작하는 선택적 함수.
|
||||
* (e.g., 역할 기반 메뉴 필터링)
|
||||
*/
|
||||
export async function loadComponent(componentName, containerSelector, domProcessor = null) {
|
||||
const container = document.querySelector(containerSelector);
|
||||
if (!container) {
|
||||
console.error(`🔴 컴포넌트를 삽입할 컨테이너를 찾을 수 없습니다: ${containerSelector}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const componentPath = config.components[componentName];
|
||||
if (!componentPath) {
|
||||
console.error(`🔴 설정 파일(config.js)에서 '${componentName}' 컴포넌트의 경로를 찾을 수 없습니다.`);
|
||||
container.innerHTML = `<p>${componentName} 로딩 실패</p>`;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(componentPath);
|
||||
if (!response.ok) {
|
||||
throw new Error(`컴포넌트 파일을 불러올 수 없습니다: ${response.statusText}`);
|
||||
}
|
||||
const htmlText = await response.text();
|
||||
|
||||
if (domProcessor) {
|
||||
// 1. 텍스트를 가상 DOM으로 파싱
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(htmlText, 'text/html');
|
||||
|
||||
// 2. DOM 프로세서(콜백)를 실행하여 DOM 조작
|
||||
await domProcessor(doc);
|
||||
|
||||
// 3. 조작된 HTML을 실제 DOM에 삽입
|
||||
container.innerHTML = doc.body.innerHTML;
|
||||
} else {
|
||||
// DOM 조작이 필요 없는 경우, 바로 삽입
|
||||
container.innerHTML = htmlText;
|
||||
}
|
||||
|
||||
console.log(`✅ '${componentName}' 컴포넌트 로딩 완료: ${containerSelector}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`🔴 '${componentName}' 컴포넌트 로딩 실패:`, error);
|
||||
container.innerHTML = `<p>${componentName} 로딩에 실패했습니다. 관리자에게 문의하세요.</p>`;
|
||||
}
|
||||
}
|
||||
40
web-ui/js/config.js
Normal file
40
web-ui/js/config.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// /js/config.js
|
||||
|
||||
// ES6 모듈을 사용하여 설정을 내보냅니다.
|
||||
// 이 파일을 통해 프로젝트의 모든 하드코딩된 값을 관리합니다.
|
||||
|
||||
export const config = {
|
||||
// API 관련 설정
|
||||
api: {
|
||||
// 로컬 개발 및 Docker 환경에서 사용하는 API 서버 포트
|
||||
port: 20005,
|
||||
// API의 기본 경로
|
||||
path: '/api',
|
||||
},
|
||||
|
||||
// 페이지 경로 설정
|
||||
paths: {
|
||||
// 로그인 페이지 경로
|
||||
loginPage: '/index.html',
|
||||
// 로그인 후 기본적으로 이동할 대시보드 경로
|
||||
defaultDashboard: '/pages/dashboard/user.html',
|
||||
// 시스템 대시보드 경로
|
||||
systemDashboard: '/pages/dashboard/system.html',
|
||||
// 그룹 리더 대시보드 경로
|
||||
groupLeaderDashboard: '/pages/dashboard/group-leader.html',
|
||||
},
|
||||
|
||||
// 공용 컴포넌트 경로 설정
|
||||
components: {
|
||||
// 사이드바 HTML 파일 경로
|
||||
sidebar: '/components/sidebar.html',
|
||||
// 네비게이션 바 HTML 파일 경로 (예상)
|
||||
navbar: '/components/navbar.html',
|
||||
},
|
||||
|
||||
// 애플리케이션 관련 기타 설정
|
||||
app: {
|
||||
// 토큰 만료 확인 주기 (밀리초 단위, 예: 5분)
|
||||
tokenRefreshInterval: 5 * 60 * 1000,
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
// js/load-navbar.js
|
||||
// 브라우저 호환 버전 - ES6 모듈 제거
|
||||
// /js/load-navbar.js
|
||||
import { getUser, clearAuthData } from './auth.js';
|
||||
import { loadComponent } from './component-loader.js';
|
||||
import { config } from './config.js';
|
||||
|
||||
// 역할 이름을 한글로 변환하는 맵
|
||||
const ROLE_NAMES = {
|
||||
@@ -11,6 +13,21 @@ const ROLE_NAMES = {
|
||||
default: '사용자',
|
||||
};
|
||||
|
||||
/**
|
||||
* 네비게이션 바 DOM을 사용자 정보와 역할에 맞게 수정하는 프로세서입니다.
|
||||
* @param {Document} doc - 파싱된 HTML 문서 객체
|
||||
*/
|
||||
function processNavbarDom(doc) {
|
||||
const currentUser = getUser();
|
||||
if (!currentUser) return;
|
||||
|
||||
// 1. 역할 기반 메뉴 필터링
|
||||
filterMenuByRole(doc, currentUser.role);
|
||||
|
||||
// 2. 사용자 정보 채우기
|
||||
populateUserInfo(doc, currentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 역할에 따라 메뉴 항목을 필터링합니다.
|
||||
* @param {Document} doc - 파싱된 HTML 문서 객체
|
||||
@@ -24,8 +41,7 @@ function filterMenuByRole(doc, userRole) {
|
||||
];
|
||||
|
||||
selectors.forEach(({ role, selector }) => {
|
||||
// 사용자가 해당 역할을 가지고 있지 않으면 메뉴 항목을 제거
|
||||
if (userRole !== role && userRole !== 'system') { // system 권한도 admin 메뉴 접근 가능
|
||||
if (userRole !== role && userRole !== 'system') {
|
||||
doc.querySelectorAll(selector).forEach(el => el.remove());
|
||||
}
|
||||
});
|
||||
@@ -40,25 +56,18 @@ function populateUserInfo(doc, user) {
|
||||
const displayName = user.name || user.username;
|
||||
const roleName = ROLE_NAMES[user.role] || ROLE_NAMES.default;
|
||||
|
||||
// 상단 바 사용자 이름
|
||||
const userNameEl = doc.getElementById('user-name');
|
||||
if (userNameEl) userNameEl.textContent = displayName;
|
||||
const elements = {
|
||||
'user-name': displayName,
|
||||
'user-role': roleName,
|
||||
'dropdown-user-fullname': displayName,
|
||||
'dropdown-user-id': `@${user.username}`,
|
||||
};
|
||||
|
||||
// 상단 바 사용자 역할
|
||||
const userRoleEl = doc.getElementById('user-role');
|
||||
if (userRoleEl) userRoleEl.textContent = roleName;
|
||||
for (const id in elements) {
|
||||
const el = doc.getElementById(id);
|
||||
if (el) el.textContent = elements[id];
|
||||
}
|
||||
|
||||
// 드롭다운 메뉴 사용자 이름
|
||||
const dropdownNameEl = doc.getElementById('dropdown-user-fullname');
|
||||
if (dropdownNameEl) dropdownNameEl.textContent = displayName;
|
||||
|
||||
// 드롭다운 메뉴 사용자 아이디
|
||||
const dropdownIdEl = doc.getElementById('dropdown-user-id');
|
||||
if (dropdownIdEl) dropdownIdEl.textContent = `@${user.username}`;
|
||||
|
||||
// Admin 버튼 제거됨
|
||||
|
||||
// System 버튼 표시 여부 결정 (system 권한만)
|
||||
const systemBtn = doc.getElementById('systemBtn');
|
||||
if (systemBtn && user.role === 'system') {
|
||||
systemBtn.style.display = 'flex';
|
||||
@@ -72,7 +81,6 @@ function setupNavbarEvents() {
|
||||
const userInfoDropdown = document.getElementById('user-info-dropdown');
|
||||
const profileDropdownMenu = document.getElementById('profile-dropdown-menu');
|
||||
|
||||
// 드롭다운 토글
|
||||
if (userInfoDropdown && profileDropdownMenu) {
|
||||
userInfoDropdown.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -81,36 +89,30 @@ function setupNavbarEvents() {
|
||||
});
|
||||
}
|
||||
|
||||
// 로그아웃 버튼
|
||||
const logoutButton = document.getElementById('dropdown-logout');
|
||||
if (logoutButton) {
|
||||
logoutButton.addEventListener('click', () => {
|
||||
if (confirm('로그아웃 하시겠습니까?')) {
|
||||
clearAuthData();
|
||||
window.location.href = '/index.html';
|
||||
window.location.href = config.paths.loginPage;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Admin 버튼 제거됨
|
||||
|
||||
// System 버튼 클릭 이벤트
|
||||
const systemButton = document.getElementById('systemBtn');
|
||||
if (systemButton) {
|
||||
systemButton.addEventListener('click', () => {
|
||||
window.location.href = '/pages/dashboard/system.html';
|
||||
window.location.href = config.paths.systemDashboard;
|
||||
});
|
||||
}
|
||||
|
||||
// Dashboard 버튼 클릭 이벤트
|
||||
const dashboardButton = document.querySelector('.dashboard-btn');
|
||||
if (dashboardButton) {
|
||||
dashboardButton.addEventListener('click', () => {
|
||||
window.location.href = '/pages/dashboard/group-leader.html';
|
||||
window.location.href = config.paths.groupLeaderDashboard;
|
||||
});
|
||||
}
|
||||
|
||||
// 외부 클릭 시 드롭다운 닫기
|
||||
document.addEventListener('click', (e) => {
|
||||
if (profileDropdownMenu && !userInfoDropdown.contains(e.target) && !profileDropdownMenu.contains(e.target)) {
|
||||
profileDropdownMenu.classList.remove('show');
|
||||
@@ -130,41 +132,17 @@ function updateTime() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 메인 로직: DOMContentLoaded 시 실행
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const navbarContainer = document.getElementById('navbar-container');
|
||||
if (!navbarContainer) return;
|
||||
|
||||
const currentUser = getUser();
|
||||
if (!currentUser) return; // 사용자가 없으면 아무 작업도 하지 않음
|
||||
|
||||
try {
|
||||
const response = await fetch('/components/navbar.html');
|
||||
const htmlText = await response.text();
|
||||
|
||||
// 1. 텍스트를 가상 DOM으로 파싱
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(htmlText, 'text/html');
|
||||
|
||||
// 2. DOM에 삽입하기 *전*에 내용 수정
|
||||
filterMenuByRole(doc, currentUser.role);
|
||||
populateUserInfo(doc, currentUser);
|
||||
|
||||
// 3. 수정 완료된 HTML을 실제 DOM에 삽입 (깜빡임 방지)
|
||||
navbarContainer.innerHTML = doc.body.innerHTML;
|
||||
|
||||
// 4. DOM에 삽입된 후에 이벤트 리스너 설정
|
||||
if (getUser()) {
|
||||
// 1. 컴포넌트 로드 및 DOM 수정
|
||||
await loadComponent('navbar', '#navbar-container', processNavbarDom);
|
||||
|
||||
// 2. DOM에 삽입된 후에 이벤트 리스너 설정
|
||||
setupNavbarEvents();
|
||||
|
||||
// 5. 실시간 시간 업데이트 시작
|
||||
// 3. 실시간 시간 업데이트 시작
|
||||
updateTime();
|
||||
setInterval(updateTime, 1000);
|
||||
|
||||
console.log('✅ 네비게이션 바 로딩 완료');
|
||||
|
||||
} catch (error) {
|
||||
console.error('🔴 네비게이션 바 로딩 중 오류 발생:', error);
|
||||
navbarContainer.innerHTML = '<p>네비게이션 바를 불러오는 데 실패했습니다.</p>';
|
||||
}
|
||||
});
|
||||
@@ -1,12 +1,17 @@
|
||||
// /js/load-sidebar.js
|
||||
import { getUser } from './auth.js';
|
||||
import { loadComponent } from './component-loader.js';
|
||||
|
||||
/**
|
||||
* 사용자 역할에 따라 사이드바 메뉴 항목을 필터링합니다.
|
||||
* 사용자 역할에 따라 사이드바 메뉴 항목을 필터링하는 DOM 프로세서입니다.
|
||||
* @param {Document} doc - 파싱된 HTML 문서 객체
|
||||
* @param {string} userRole - 현재 사용자의 역할
|
||||
*/
|
||||
function filterSidebarByRole(doc, userRole) {
|
||||
function filterSidebarByRole(doc) {
|
||||
const currentUser = getUser();
|
||||
if (!currentUser) return; // 비로그인 상태면 필터링하지 않음
|
||||
|
||||
const userRole = currentUser.role;
|
||||
|
||||
// 'system' 역할은 모든 메뉴를 볼 수 있으므로 필터링하지 않음
|
||||
if (userRole === 'system') {
|
||||
return;
|
||||
@@ -16,7 +21,7 @@ function filterSidebarByRole(doc, userRole) {
|
||||
const roleClassMap = {
|
||||
admin: '.admin-only',
|
||||
leader: '.leader-only',
|
||||
user: '.user-only', // 또는 'worker-only' 등, sidebar.html에 정의된 클래스에 맞춰야 함
|
||||
user: '.user-only',
|
||||
support: '.support-only'
|
||||
};
|
||||
|
||||
@@ -33,35 +38,10 @@ function filterSidebarByRole(doc, userRole) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const sidebarContainer = document.getElementById('sidebar-container');
|
||||
if (!sidebarContainer) return;
|
||||
|
||||
const currentUser = getUser();
|
||||
if (!currentUser) return; // 비로그인 상태면 사이드바를 로드하지 않음
|
||||
|
||||
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>';
|
||||
// 페이지 로드 시 사이드바를 로드하고 역할에 따라 필터링합니다.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 'getUser'를 통해 로그인 상태 확인. 비로그인 시 아무 작업도 하지 않음.
|
||||
if (getUser()) {
|
||||
loadComponent('sidebar', '#sidebar-container', filterSidebarByRole);
|
||||
}
|
||||
});
|
||||
@@ -1,16 +1,8 @@
|
||||
// /js/login.js
|
||||
// ES6 모듈 의존성 제거 - 브라우저 호환성 개선
|
||||
|
||||
// 인증 데이터 저장 함수 (직접 구현)
|
||||
function saveAuthData(token, user) {
|
||||
localStorage.setItem('token', token);
|
||||
localStorage.setItem('user', JSON.stringify(user));
|
||||
}
|
||||
|
||||
function clearAuthData() {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
}
|
||||
import { saveAuthData, clearAuthData } from './auth.js';
|
||||
import { redirectToDefaultDashboard } from './navigation.js';
|
||||
// api-helper.js가 ES6 모듈로 변환되면 import를 사용해야 합니다.
|
||||
// import { login } from './api-helper.js';
|
||||
|
||||
document.getElementById('loginForm').addEventListener('submit', async function (e) {
|
||||
e.preventDefault();
|
||||
@@ -28,27 +20,18 @@ document.getElementById('loginForm').addEventListener('submit', async function (
|
||||
errorDiv.style.display = 'none';
|
||||
|
||||
try {
|
||||
// API 헬퍼를 통해 로그인 요청 (window 객체에서 가져오기)
|
||||
// 현재는 window 객체를 통해 호출하지만, 향후 모듈화 필요
|
||||
const result = await window.login(username, password);
|
||||
|
||||
if (result.success && result.data && result.data.token) {
|
||||
// 인증 정보 저장
|
||||
// auth.js에서 가져온 함수로 인증 정보 저장
|
||||
saveAuthData(result.data.token, result.data.user);
|
||||
|
||||
// 백엔드가 지정한 URL로 리디렉션
|
||||
const redirectUrl = result.data.redirectUrl || '/pages/dashboard/user.html'; // 혹시 모를 예외처리
|
||||
|
||||
// 부드러운 화면 전환 효과
|
||||
document.body.style.transition = 'opacity 0.3s ease-out';
|
||||
document.body.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = redirectUrl;
|
||||
}, 300);
|
||||
// navigation.js를 통해 리디렉션
|
||||
redirectToDefaultDashboard(result.data.redirectUrl);
|
||||
|
||||
} else {
|
||||
// 이 케이스는 api-helper에서 throw new Error()로 처리되어 catch 블록으로 바로 이동합니다.
|
||||
// 하지만, 만약의 경우를 대비해 방어 코드를 남겨둡니다.
|
||||
// api-helper가 에러를 throw하므로 이 블록은 실행될 가능성이 낮음
|
||||
clearAuthData();
|
||||
errorDiv.textContent = result.error || '로그인에 실패했습니다.';
|
||||
errorDiv.style.display = 'block';
|
||||
@@ -56,7 +39,6 @@ document.getElementById('loginForm').addEventListener('submit', async function (
|
||||
} catch (err) {
|
||||
console.error('로그인 오류:', err);
|
||||
clearAuthData();
|
||||
// api-helper에서 보낸 에러 메시지를 표시
|
||||
errorDiv.textContent = err.message || '서버 연결에 실패했습니다.';
|
||||
errorDiv.style.display = 'block';
|
||||
} finally {
|
||||
|
||||
55
web-ui/js/navigation.js
Normal file
55
web-ui/js/navigation.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// /js/navigation.js
|
||||
import { config } from './config.js';
|
||||
|
||||
/**
|
||||
* 지정된 URL로 페이지를 리디렉션합니다.
|
||||
* @param {string} url - 이동할 URL
|
||||
*/
|
||||
function redirect(url) {
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 페이지로 리디렉션합니다.
|
||||
*/
|
||||
export function redirectToLogin() {
|
||||
console.log(`🔄 로그인 페이지로 이동합니다: ${config.paths.loginPage}`);
|
||||
redirect(config.paths.loginPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 기본 대시보드 페이지로 리디렉션합니다.
|
||||
* 백엔드가 지정한 URL이 있으면 그곳으로, 없으면 기본 URL로 이동합니다.
|
||||
* @param {string} [backendRedirectUrl=null] - 백엔드에서 전달받은 리디렉션 URL
|
||||
*/
|
||||
export function redirectToDefaultDashboard(backendRedirectUrl = null) {
|
||||
const destination = backendRedirectUrl || config.paths.defaultDashboard;
|
||||
console.log(`🔄 대시보드로 이동합니다: ${destination}`);
|
||||
|
||||
// 부드러운 화면 전환 효과
|
||||
document.body.style.transition = 'opacity 0.3s ease-out';
|
||||
document.body.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
redirect(destination);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
/**
|
||||
* 시스템 대시보드 페이지로 리디렉션합니다.
|
||||
*/
|
||||
export function redirectToSystemDashboard() {
|
||||
console.log(`🔄 시스템 대시보드로 이동합니다: ${config.paths.systemDashboard}`);
|
||||
redirect(config.paths.systemDashboard);
|
||||
}
|
||||
|
||||
/**
|
||||
* 그룹 리더 대시보드 페이지로 리디렉션합니다.
|
||||
*/
|
||||
export function redirectToGroupLeaderDashboard() {
|
||||
console.log(`🔄 그룹 리더 대시보드로 이동합니다: ${config.paths.groupLeaderDashboard}`);
|
||||
redirect(config.paths.groupLeaderDashboard);
|
||||
}
|
||||
|
||||
// 필요에 따라 더 많은 리디렉션 함수를 추가할 수 있습니다.
|
||||
// export function redirectToUserProfile() { ... }
|
||||
Reference in New Issue
Block a user