// AI Server Admin Login JavaScript class LoginManager { constructor() { this.baseUrl = window.location.origin; this.init(); } init() { // Check if already logged in this.checkExistingAuth(); // Setup form submission document.getElementById('login-form').addEventListener('submit', (e) => { e.preventDefault(); this.handleLogin(); }); // Setup enter key handling document.addEventListener('keypress', (e) => { if (e.key === 'Enter') { this.handleLogin(); } }); // Auto-focus username field document.getElementById('username').focus(); } async checkExistingAuth() { const token = localStorage.getItem('ai_admin_token'); if (token) { try { console.log('Checking existing token...'); // Verify token is still valid const response = await fetch(`${this.baseUrl}/admin/verify-token`, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { console.log('Token is valid, redirecting to admin...'); // Token is valid, redirect to admin window.location.href = '/admin'; return; } else { console.log('Token verification failed with status:', response.status); } } catch (error) { console.log('Token verification failed:', error); } // Token is invalid, remove it console.log('Removing invalid token...'); localStorage.removeItem('ai_admin_token'); localStorage.removeItem('ai_admin_user'); } } async handleLogin() { const username = document.getElementById('username').value.trim(); const password = document.getElementById('password').value; const rememberMe = document.getElementById('remember-me').checked; // Validation if (!username || !password) { this.showError('Please enter both username and password'); return; } // Show loading state this.setLoading(true); this.hideError(); try { const response = await fetch(`${this.baseUrl}/admin/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password, remember_me: rememberMe }) }); const data = await response.json(); if (response.ok && data.success) { // Store JWT token localStorage.setItem('ai_admin_token', data.token); // Store user info localStorage.setItem('ai_admin_user', JSON.stringify(data.user)); console.log('Token stored:', data.token.substring(0, 20) + '...'); console.log('User stored:', data.user); // Show success message this.showSuccess('Login successful! Redirecting...'); // Redirect after short delay setTimeout(() => { window.location.href = '/admin'; }, 1000); } else { this.showError(data.message || 'Login failed. Please check your credentials.'); } } catch (error) { console.error('Login error:', error); this.showError('Connection error. Please try again.'); } finally { this.setLoading(false); } } setLoading(loading) { const btn = document.getElementById('login-btn'); const icon = btn.querySelector('i'); if (loading) { btn.disabled = true; btn.classList.add('loading'); icon.className = 'fas fa-spinner'; btn.querySelector('span') ? btn.querySelector('span').textContent = 'Signing In...' : btn.innerHTML = ' Signing In...'; } else { btn.disabled = false; btn.classList.remove('loading'); icon.className = 'fas fa-sign-in-alt'; btn.innerHTML = ' Sign In'; } } showError(message) { const errorDiv = document.getElementById('error-message'); const errorText = document.getElementById('error-text'); errorText.textContent = message; errorDiv.style.display = 'flex'; // Auto-hide after 5 seconds setTimeout(() => { this.hideError(); }, 5000); } hideError() { document.getElementById('error-message').style.display = 'none'; } showSuccess(message) { // Create success message element if it doesn't exist let successDiv = document.getElementById('success-message'); if (!successDiv) { successDiv = document.createElement('div'); successDiv.id = 'success-message'; successDiv.className = 'success-message'; successDiv.innerHTML = ` ${message} `; // Add CSS for success message const style = document.createElement('style'); style.textContent = ` .success-message { background: #d5f4e6; border: 1px solid #27ae60; border-radius: 8px; padding: 0.75rem; margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem; color: #27ae60; font-size: 0.9rem; animation: slideDown 0.3s ease-out; } @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } `; document.head.appendChild(style); // Insert before error message const errorDiv = document.getElementById('error-message'); errorDiv.parentNode.insertBefore(successDiv, errorDiv); } else { document.getElementById('success-text').textContent = message; successDiv.style.display = 'flex'; } } } // Password toggle functionality function togglePassword() { const passwordInput = document.getElementById('password'); const passwordEye = document.getElementById('password-eye'); if (passwordInput.type === 'password') { passwordInput.type = 'text'; passwordEye.className = 'fas fa-eye-slash'; } else { passwordInput.type = 'password'; passwordEye.className = 'fas fa-eye'; } } // Initialize login manager when page loads document.addEventListener('DOMContentLoaded', () => { new LoginManager(); }); // Security: Clear sensitive data on page unload window.addEventListener('beforeunload', () => { // Clear password field const passwordField = document.getElementById('password'); if (passwordField) { passwordField.value = ''; } });