// DOM Elements const loginForm = document.getElementById('loginForm'); const emailInput = document.getElementById('email'); const passwordInput = document.getElementById('password'); const passwordToggle = document.getElementById('passwordToggle'); const loginButton = document.getElementById('loginButton'); const toast = document.getElementById('toast'); // Error message elements const emailError = document.getElementById('emailError'); const passwordError = document.getElementById('passwordError'); const generalError = document.getElementById('generalError'); // API Configuration const API_BASE_URL = '/api/v1'; const LOGIN_ENDPOINT = `${API_BASE_URL}/auth/login`; // Password visibility toggle passwordToggle.addEventListener('click', () => { const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password'; passwordInput.setAttribute('type', type); const icon = passwordToggle.querySelector('.toggle-icon'); icon.textContent = type === 'password' ? '👁️' : '🙈'; }); // Form validation functions const validateEmail = (email) => { return true; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; const validatePassword = (password) => { return password.length >= 6; }; const showError = (element, message) => { element.textContent = message; element.style.display = 'block'; }; const hideError = (element) => { element.textContent = ''; element.style.display = 'none'; }; const clearAllErrors = () => { hideError(emailError); hideError(passwordError); generalError.classList.remove('show'); emailInput.classList.remove('error'); passwordInput.classList.remove('error'); }; // Real-time validation emailInput.addEventListener('blur', () => { const email = emailInput.value.trim(); if (email && !validateEmail(email)) { showError(emailError, 'Please enter a valid email address'); emailInput.classList.add('error'); } else { hideError(emailError); emailInput.classList.remove('error'); } }); passwordInput.addEventListener('blur', () => { const password = passwordInput.value; if (password && !validatePassword(password)) { showError(passwordError, 'Password must be at least 6 characters long'); passwordInput.classList.add('error'); } else { hideError(passwordError); passwordInput.classList.remove('error'); } }); // Clear errors on input emailInput.addEventListener('input', () => { if (emailInput.classList.contains('error')) { hideError(emailError); emailInput.classList.remove('error'); } }); passwordInput.addEventListener('input', () => { if (passwordInput.classList.contains('error')) { hideError(passwordError); passwordInput.classList.remove('error'); } }); // Show toast notification const showToast = (message, type = 'success') => { const toastContent = toast.querySelector('.toast-content'); const toastIcon = toast.querySelector('.toast-icon'); const toastMessage = toast.querySelector('.toast-message'); // Set icon and color based on type if (type === 'success') { toastIcon.textContent = '✓'; toast.style.background = 'var(--success)'; } else if (type === 'error') { toastIcon.textContent = '✕'; toast.style.background = 'var(--error)'; } toastMessage.textContent = message; toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 4000); }; // Set loading state const setLoadingState = (loading) => { if (loading) { loginButton.classList.add('loading'); loginButton.disabled = true; } else { loginButton.classList.remove('loading'); loginButton.disabled = false; } }; // Make login API request const makeLoginRequest = async (credentials) => { try { const response = await fetch(LOGIN_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(credentials) }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || `HTTP error! status: ${response.status}`); } return data; } catch (error) { // Handle network errors or API errors if (error.name === 'TypeError' && error.message.includes('fetch')) { throw new Error('Network error. Please check your connection and try again.'); } throw error; } }; // Handle successful login const handleLoginSuccess = (data) => { // Store authentication data if (data.token) { localStorage.setItem('taskflow_token', data.token); } if (data.refreshToken) { localStorage.setItem('taskflow_refresh_token', data.refreshToken); } if (data.user) { localStorage.setItem('taskflow_user', JSON.stringify(data.user)); } // Show success message showToast('Login successful! Redirecting to dashboard...', 'success'); // Redirect to dashboard after a short delay setTimeout(() => { window.location.href = 'index.html'; // or wherever the dashboard is located }, 2000); }; // Handle login error const handleLoginError = (error) => { console.error('Login error:', error); let errorMessage = 'An unexpected error occurred. Please try again.'; if (error.message.includes('Invalid credentials') || error.message.includes('Unauthorized') || error.message.includes('401')) { errorMessage = 'Invalid email or password. Please check your credentials and try again.'; } else if (error.message.includes('Network error')) { errorMessage = error.message; } else if (error.message.includes('Too many attempts')) { errorMessage = 'Too many login attempts. Please try again later.'; } generalError.textContent = errorMessage; generalError.classList.add('show'); showToast(errorMessage, 'error'); }; // Form submission handler loginForm.addEventListener('submit', async (e) => { e.preventDefault(); // Clear previous errors clearAllErrors(); // Get form data const email = emailInput.value.trim(); const password = passwordInput.value; const rememberMe = document.getElementById('rememberMe').checked; // Validate inputs let hasErrors = false; if (!email) { showError(emailError, 'Email is required'); emailInput.classList.add('error'); hasErrors = true; } else if (!validateEmail(email)) { showError(emailError, 'Please enter a valid email address'); emailInput.classList.add('error'); hasErrors = true; } if (!password) { showError(passwordError, 'Password is required'); passwordInput.classList.add('error'); hasErrors = true; } else if (!validatePassword(password)) { showError(passwordError, 'Password must be at least 6 characters long'); passwordInput.classList.add('error'); hasErrors = true; } if (hasErrors) { return; } // Set loading state setLoadingState(true); try { // Prepare request payload const credentials = { email, password, rememberMe }; // Make API request const response = await makeLoginRequest(credentials); // Handle success handleLoginSuccess(response); } catch (error) { // Handle error handleLoginError(error); } finally { // Remove loading state setLoadingState(false); } }); // Social login handlers document.querySelector('.btn-google').addEventListener('click', () => { // In a real application, this would initiate OAuth flow showToast('Google login would be initiated here', 'success'); // Simulate OAuth redirect setTimeout(() => { window.location.href = `${API_BASE_URL}/auth/google?redirect_uri=${encodeURIComponent(window.location.origin + '/dashboard')}`; }, 1000); }); document.querySelector('.btn-microsoft').addEventListener('click', () => { // In a real application, this would initiate OAuth flow showToast('Microsoft login would be initiated here', 'success'); // Simulate OAuth redirect setTimeout(() => { window.location.href = `${API_BASE_URL}/auth/microsoft?redirect_uri=${encodeURIComponent(window.location.origin + '/dashboard')}`; }, 1000); }); // Forgot password handler document.querySelector('.forgot-password').addEventListener('click', (e) => { e.preventDefault(); const email = emailInput.value.trim(); if (email && validateEmail(email)) { showToast(`Password reset link sent to ${email}`, 'success'); } else { showToast('Please enter a valid email address first', 'error'); emailInput.focus(); } }); // Sign up link handler document.querySelector('a[href="#signup"]').addEventListener('click', (e) => { e.preventDefault(); window.location.href = 'signup.html'; // Redirect to signup page }); // Check if user is already logged in window.addEventListener('load', () => { const token = localStorage.getItem('taskflow_token'); if (token) { // Verify token is still valid (in a real app, you'd make an API call) showToast('You are already logged in. Redirecting...', 'success'); setTimeout(() => { window.location.href = 'index.html'; }, 2000); } }); // Demo credentials helper (for development/demo purposes) const addDemoCredentials = () => { const demoButton = document.createElement('button'); demoButton.type = 'button'; demoButton.className = 'btn btn-secondary btn-full'; demoButton.textContent = 'Use Demo Credentials'; demoButton.style.marginTop = '1rem'; demoButton.style.fontSize = '0.875rem'; demoButton.addEventListener('click', () => { emailInput.value = 'demo@taskflow.com'; passwordInput.value = 'demo123'; showToast('Demo credentials filled. Click Sign In to continue.', 'success'); }); // Add after the social login section const socialLogin = document.querySelector('.social-login'); socialLogin.appendChild(demoButton); }; // Add demo credentials in development if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') { addDemoCredentials(); }