| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>WiFi Attendance Tracker - Login</title> |
| | <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> |
| | <style> |
| | * { |
| | margin: 0; |
| | padding: 0; |
| | box-sizing: border-box; |
| | } |
| | |
| | body { |
| | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | min-height: 100vh; |
| | display: flex; |
| | align-items: center; |
| | justify-content: center; |
| | } |
| | |
| | .login-container { |
| | background: white; |
| | padding: 2rem; |
| | border-radius: 15px; |
| | box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); |
| | width: 100%; |
| | max-width: 400px; |
| | text-align: center; |
| | } |
| | |
| | .login-header { |
| | margin-bottom: 2rem; |
| | } |
| | |
| | .login-header i { |
| | font-size: 3rem; |
| | color: #667eea; |
| | margin-bottom: 1rem; |
| | } |
| | |
| | .login-header h1 { |
| | color: #333; |
| | font-size: 1.8rem; |
| | margin-bottom: 0.5rem; |
| | } |
| | |
| | .login-header p { |
| | color: #666; |
| | font-size: 0.9rem; |
| | } |
| | |
| | .form-group { |
| | margin-bottom: 1.5rem; |
| | text-align: left; |
| | } |
| | |
| | .form-group label { |
| | display: block; |
| | margin-bottom: 0.5rem; |
| | color: #333; |
| | font-weight: 500; |
| | } |
| | |
| | .password-input-container { |
| | position: relative; |
| | } |
| | |
| | .form-group input { |
| | width: 100%; |
| | padding: 0.75rem; |
| | border: 2px solid #e1e5e9; |
| | border-radius: 8px; |
| | font-size: 1rem; |
| | transition: border-color 0.3s ease; |
| | } |
| | |
| | .form-group input:focus { |
| | outline: none; |
| | border-color: #667eea; |
| | } |
| | |
| | .toggle-password { |
| | position: absolute; |
| | right: 10px; |
| | top: 50%; |
| | transform: translateY(-50%); |
| | background: none; |
| | border: none; |
| | color: #666; |
| | cursor: pointer; |
| | font-size: 1rem; |
| | } |
| | |
| | .login-btn { |
| | width: 100%; |
| | padding: 0.75rem; |
| | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | color: white; |
| | border: none; |
| | border-radius: 8px; |
| | font-size: 1rem; |
| | font-weight: 600; |
| | cursor: pointer; |
| | transition: transform 0.2s ease; |
| | } |
| | |
| | .login-btn:hover { |
| | transform: translateY(-2px); |
| | } |
| | |
| | .login-btn:disabled { |
| | opacity: 0.6; |
| | cursor: not-allowed; |
| | transform: none; |
| | } |
| | |
| | .error-message { |
| | background: #fee; |
| | color: #c33; |
| | padding: 0.75rem; |
| | border-radius: 8px; |
| | margin-bottom: 1rem; |
| | border-left: 4px solid #c33; |
| | display: none; |
| | } |
| | |
| | .loading { |
| | display: none; |
| | margin-top: 1rem; |
| | } |
| | |
| | .loading i { |
| | animation: spin 1s linear infinite; |
| | } |
| | |
| | @keyframes spin { |
| | 0% { transform: rotate(0deg); } |
| | 100% { transform: rotate(360deg); } |
| | } |
| | |
| | .footer { |
| | margin-top: 2rem; |
| | padding-top: 1rem; |
| | border-top: 1px solid #eee; |
| | color: #666; |
| | font-size: 0.8rem; |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <div class="login-container"> |
| | <div class="login-header"> |
| | <i class="fas fa-wifi"></i> |
| | <h1>WiFi Attendance Tracker</h1> |
| | <p>Please enter your password to access the dashboard</p> |
| | </div> |
| |
|
| | <div id="errorMessage" class="error-message"></div> |
| |
|
| | <form id="loginForm"> |
| | <div class="form-group"> |
| | <label for="password">Dashboard Password</label> |
| | <div class="password-input-container"> |
| | <input type="password" id="password" name="password" required placeholder="Enter dashboard password" autocomplete="current-password"> |
| | <button type="button" class="toggle-password" onclick="togglePassword()"> |
| | <i class="fas fa-eye" id="toggleIcon"></i> |
| | </button> |
| | </div> |
| | </div> |
| |
|
| | <button type="submit" class="login-btn" id="loginBtn"> |
| | <i class="fas fa-sign-in-alt"></i> Access Dashboard |
| | </button> |
| | </form> |
| |
|
| | <div class="loading" id="loading"> |
| | <i class="fas fa-spinner"></i> Authenticating... |
| | </div> |
| |
|
| | <div class="footer"> |
| | <p>Default password: <strong>admin123</strong></p> |
| | <p>Advanced Employee Management System</p> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | function togglePassword() { |
| | const passwordInput = document.getElementById('password'); |
| | const toggleIcon = document.getElementById('toggleIcon'); |
| | |
| | if (passwordInput.type === 'password') { |
| | passwordInput.type = 'text'; |
| | toggleIcon.className = 'fas fa-eye-slash'; |
| | } else { |
| | passwordInput.type = 'password'; |
| | toggleIcon.className = 'fas fa-eye'; |
| | } |
| | } |
| | |
| | function showError(message) { |
| | const errorDiv = document.getElementById('errorMessage'); |
| | errorDiv.textContent = message; |
| | errorDiv.style.display = 'block'; |
| | } |
| | |
| | function hideError() { |
| | const errorDiv = document.getElementById('errorMessage'); |
| | errorDiv.style.display = 'none'; |
| | } |
| | |
| | function setLoading(loading) { |
| | const loginBtn = document.getElementById('loginBtn'); |
| | const loadingDiv = document.getElementById('loading'); |
| | const form = document.getElementById('loginForm'); |
| | |
| | if (loading) { |
| | loginBtn.disabled = true; |
| | loadingDiv.style.display = 'block'; |
| | form.style.opacity = '0.6'; |
| | } else { |
| | loginBtn.disabled = false; |
| | loadingDiv.style.display = 'none'; |
| | form.style.opacity = '1'; |
| | } |
| | } |
| | |
| | document.getElementById('loginForm').addEventListener('submit', async function(e) { |
| | e.preventDefault(); |
| | |
| | const password = document.getElementById('password').value; |
| | |
| | if (!password) { |
| | showError('Please enter a password'); |
| | return; |
| | } |
| | |
| | hideError(); |
| | setLoading(true); |
| | |
| | try { |
| | const response = await fetch('/api/login', { |
| | method: 'POST', |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | }, |
| | body: JSON.stringify({ password: password }) |
| | }); |
| | |
| | const result = await response.json(); |
| | |
| | if (result.success) { |
| | |
| | window.location.href = '/dashboard'; |
| | } else { |
| | showError(result.message || 'Invalid password'); |
| | } |
| | } catch (error) { |
| | console.error('Login error:', error); |
| | showError('Connection error. Please try again.'); |
| | } finally { |
| | setLoading(false); |
| | } |
| | }); |
| | |
| | |
| | document.addEventListener('DOMContentLoaded', function() { |
| | document.getElementById('password').focus(); |
| | }); |
| | |
| | |
| | document.getElementById('password').addEventListener('keypress', function(e) { |
| | if (e.key === 'Enter') { |
| | document.getElementById('loginForm').dispatchEvent(new Event('submit')); |
| | } |
| | }); |
| | </script> |
| | </body> |
| | </html> |
| |
|
| |
|