Add waiting system application files
- Add main application files (main.py, models.py, schemas.py, etc.) - Add routers for all features (waiting, attendance, members, etc.) - Add HTML templates for admin and user interfaces - Add migration scripts and utility files - Add Docker configuration - Add documentation files - Add .gitignore to exclude database and cache files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
189
static/js/logout.js
Normal file
189
static/js/logout.js
Normal file
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* Centralized Logout Logic
|
||||
* Handles modal injection, display, and API interactions for logging out.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
// Inject Logout Modal HTML and Styles if they don't exist
|
||||
function injectLogoutModal() {
|
||||
if (document.getElementById('common-logout-modal')) return;
|
||||
|
||||
const modalHtml = `
|
||||
<div id="common-logout-modal" class="common-modal-overlay">
|
||||
<div class="common-modal-content">
|
||||
<h2 class="common-modal-title">로그아웃</h2>
|
||||
<p class="common-modal-message">정말 로그아웃 하시겠습니까?</p>
|
||||
<div class="common-modal-actions">
|
||||
<button id="common-logout-cancel" class="common-btn common-btn-secondary">취소</button>
|
||||
<button id="common-logout-confirm" class="common-btn common-btn-primary">로그아웃</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const styleHtml = `
|
||||
<style>
|
||||
.common-modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 99999;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(2px);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.common-modal-overlay.active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
.common-modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 16px;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
text-align: center;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
transform: scale(0.95);
|
||||
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
.common-modal-overlay.active .common-modal-content {
|
||||
transform: scale(1);
|
||||
}
|
||||
.common-modal-title {
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.common-modal-message {
|
||||
font-size: 16px;
|
||||
color: #7f8c8d;
|
||||
margin-bottom: 25px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.common-modal-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
.common-btn {
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
flex: 1;
|
||||
}
|
||||
.common-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
.common-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.common-btn-primary {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
.common-btn-secondary {
|
||||
background: #f1f3f5;
|
||||
color: #495057;
|
||||
}
|
||||
.common-btn-secondary:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
document.head.insertAdjacentHTML('beforeend', styleHtml);
|
||||
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||||
|
||||
// Bind Events
|
||||
document.getElementById('common-logout-cancel').addEventListener('click', closeLogoutModal);
|
||||
document.getElementById('common-logout-confirm').addEventListener('click', executeLogout);
|
||||
|
||||
// Close on overlay click
|
||||
document.getElementById('common-logout-modal').addEventListener('click', function (e) {
|
||||
if (e.target === this) closeLogoutModal();
|
||||
});
|
||||
}
|
||||
|
||||
// Expose global functions
|
||||
window.showLogoutModal = function () {
|
||||
injectLogoutModal(); // Ensure it exists
|
||||
const modal = document.getElementById('common-logout-modal');
|
||||
// Small timeout to allow display:flex to apply before opacity transition
|
||||
modal.style.display = 'flex';
|
||||
requestAnimationFrame(() => {
|
||||
modal.classList.add('active');
|
||||
});
|
||||
};
|
||||
|
||||
window.closeLogoutModal = function () {
|
||||
const modal = document.getElementById('common-logout-modal');
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
setTimeout(() => {
|
||||
modal.style.display = 'none';
|
||||
}, 300); // Wait for transition
|
||||
}
|
||||
};
|
||||
|
||||
// Alias for backward compatibility with existing buttons
|
||||
window.logout = function (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
window.showLogoutModal();
|
||||
};
|
||||
|
||||
window.executeLogout = async function () {
|
||||
try {
|
||||
// Close SSE connection if exists
|
||||
if (window.eventSource) {
|
||||
window.eventSource.close();
|
||||
}
|
||||
|
||||
// Call API
|
||||
await fetch('/api/auth/logout', { method: 'POST' });
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
} finally {
|
||||
// Clear all possible Storage items
|
||||
const keysToRemove = [
|
||||
'access_token',
|
||||
'refresh_token',
|
||||
'selected_store_id',
|
||||
'selected_store_name',
|
||||
'selected_store_code',
|
||||
'username',
|
||||
'user_role',
|
||||
'superadmin_franchise_context',
|
||||
'store_management_context'
|
||||
];
|
||||
|
||||
keysToRemove.forEach(key => localStorage.removeItem(key));
|
||||
|
||||
// Redirect
|
||||
window.location.replace('/login');
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize on load
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', injectLogoutModal);
|
||||
} else {
|
||||
injectLogoutModal();
|
||||
}
|
||||
|
||||
})();
|
||||
21
static/js/screen-monitor.js
Normal file
21
static/js/screen-monitor.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// 화면 크기 및 방향 모니터링 (태블릿 최적화 디버깅)
|
||||
function logScreenInfo() {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
const orientation = width > height ? 'landscape' : 'portrait';
|
||||
const deviceType = width < 600 ? 'mobile' :
|
||||
width < 768 ? 'small-tablet' :
|
||||
width < 1024 ? 'tablet' : 'large-tablet/desktop';
|
||||
|
||||
console.log(`📱 Screen Info: ${width}x${height} (${orientation}) - ${deviceType}`);
|
||||
}
|
||||
|
||||
// 초기 로드 시 화면 정보 출력
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
logScreenInfo();
|
||||
});
|
||||
|
||||
// 화면 크기 변경 시 정보 출력 (회전 등)
|
||||
window.addEventListener('resize', () => {
|
||||
logScreenInfo();
|
||||
});
|
||||
Reference in New Issue
Block a user