summaryrefslogtreecommitdiff
path: root/static/login-script.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/login-script.js')
-rw-r--r--static/login-script.js341
1 files changed, 341 insertions, 0 deletions
diff --git a/static/login-script.js b/static/login-script.js
new file mode 100644
index 0000000..da69c7b
--- /dev/null
+++ b/static/login-script.js
@@ -0,0 +1,341 @@
+// 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 = 'https://api.taskflow.com/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) => {
+ 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();
+}