// public/script.js // Handles frontend logic for login, registration, and todo management document.addEventListener('DOMContentLoaded', () => { const path = window.location.pathname; // --- Page-Specific Logic --- if (path === '/login' || path.endsWith('login.html')) { setupLoginForm(); } else if (path === '/register' || path.endsWith('register.html')) { setupRegisterForm(); } else if (path === '/' || path.endsWith('index.html')) { // User should be authenticated to be here (handled by viewRoutes) setupTodoPage(); } }); // --- Authentication Form Handlers --- function setupLoginForm() { const loginForm = document.getElementById('login-form'); const errorMessage = document.getElementById('error-message'); if (loginForm) { loginForm.addEventListener('submit', async (event) => { event.preventDefault(); // Prevent default form submission errorMessage.textContent = ''; // Clear previous errors const username = loginForm.username.value; const password = loginForm.password.value; try { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); const result = await response.json(); if (response.ok) { // Login successful, redirect to the main todo page window.location.href = '/'; // Redirect to home page } else { // Display error message from server errorMessage.textContent = result.message || 'Login fehlgeschlagen.'; } } catch (error) { console.error('Login request failed:', error); errorMessage.textContent = 'Ein Netzwerkfehler ist aufgetreten. Bitte versuchen Sie es erneut.'; } }); } } function setupRegisterForm() { const registerForm = document.getElementById('register-form'); const errorMessage = document.getElementById('error-message'); const successMessage = document.getElementById('success-message'); if (registerForm) { registerForm.addEventListener('submit', async (event) => { event.preventDefault(); errorMessage.textContent = ''; successMessage.textContent = ''; const username = registerForm.username.value; const password = registerForm.password.value; const confirmPassword = registerForm['confirm-password'].value; if (password !== confirmPassword) { errorMessage.textContent = 'Passwörter stimmen nicht überein.'; return; } try { const response = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); const result = await response.json(); if (response.ok) { successMessage.textContent = result.message + ' Sie werden zum Login weitergeleitet...'; registerForm.reset(); // Clear the form // Redirect to login page after a short delay setTimeout(() => { window.location.href = '/login'; }, 2000); // 2 seconds delay } else { errorMessage.textContent = result.message || 'Registrierung fehlgeschlagen.'; } } catch (error) { console.error('Registration request failed:', error); errorMessage.textContent = 'Ein Netzwerkfehler ist aufgetreten. Bitte versuchen Sie es erneut.'; } }); } } // --- Todo Page Logic --- function setupTodoPage() { const addTodoForm = document.getElementById('add-todo-form'); const newTodoInput = document.getElementById('new-todo-input'); const todoList = document.getElementById('todo-list'); const logoutButton = document.getElementById('logout-button'); const errorMessage = document.getElementById('error-message'); // --- Event Listeners --- // Add Todo Form Submission if (addTodoForm) { addTodoForm.addEventListener('submit', async (event) => { event.preventDefault(); const task = newTodoInput.value.trim(); if (task) { await addTodoItem(task); newTodoInput.value = ''; // Clear input field } }); } // Todo List Click Handler (for checkboxes and delete buttons) if (todoList) { todoList.addEventListener('click', async (event) => { const target = event.target; const todoItem = target.closest('.todo-item'); // Find the parent li element if (!todoItem) return; // Click was not inside a todo item const todoId = todoItem.dataset.id; // Handle Checkbox Click (Toggle Completion) if (target.type === 'checkbox') { const isCompleted = target.checked; await updateTodoStatus(todoId, isCompleted); } // Handle Delete Button Click if (target.classList.contains('btn-delete')) { await deleteTodoItem(todoId); } }); } // Logout Button Click if (logoutButton) { logoutButton.addEventListener('click', async () => { errorMessage.textContent = ''; // Clear errors try { const response = await fetch('/api/auth/logout', { method: 'POST' }); if (response.ok) { // Logout successful, redirect to login page window.location.href = '/login'; } else { const result = await response.json(); errorMessage.textContent = result.message || 'Logout fehlgeschlagen.'; } } catch (error) { console.error('Logout failed:', error); errorMessage.textContent = 'Logout fehlgeschlagen. Netzwerkfehler.'; } }); } // --- API Call Functions --- // Fetch Todos from Server async function fetchTodos() { errorMessage.textContent = ''; try { const response = await fetch('/api/todos'); // GET request by default if (response.status === 401 || response.status === 403) { // If unauthorized (e.g., token expired), redirect to login window.location.href = '/login'; return; } if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const todos = await response.json(); renderTodoList(todos); } catch (error) { console.error('Error fetching todos:', error); errorMessage.textContent = 'Fehler beim Laden der Todos.'; // Handle error display or potentially redirect to login if it's an auth issue } } // Add a New Todo Item async function addTodoItem(task) { errorMessage.textContent = ''; try { const response = await fetch('/api/todos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ task }), }); if (response.status === 401 || response.status === 403) { window.location.href = '/login'; return; } if (!response.ok) { const result = await response.json(); throw new Error(result.message || 'Fehler beim Hinzufügen'); } const newTodo = await response.json(); addTodoToDOM(newTodo); // Add the new todo to the page immediately } catch (error) { console.error('Error adding todo:', error); errorMessage.textContent = `Fehler beim Hinzufügen: ${error.message}`; } } // Update Todo Completion Status async function updateTodoStatus(id, isCompleted) { errorMessage.textContent = ''; try { const response = await fetch(`/api/todos/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ is_completed: isCompleted }), }); if (response.status === 401 || response.status === 403) { window.location.href = '/login'; return; } if (!response.ok) { const result = await response.json(); throw new Error(result.message || 'Fehler beim Aktualisieren'); } const updatedTodo = await response.json(); // Update the specific todo item in the DOM const todoElement = todoList.querySelector(`li[data-id="${id}"]`); if (todoElement) { todoElement.classList.toggle('completed', updatedTodo.is_completed); const checkbox = todoElement.querySelector('input[type="checkbox"]'); if(checkbox) checkbox.checked = updatedTodo.is_completed; } } catch (error) { console.error('Error updating todo status:', error); errorMessage.textContent = `Fehler beim Aktualisieren: ${error.message}`; // Optional: Revert checkbox state on error const todoElement = todoList.querySelector(`li[data-id="${id}"]`); if(todoElement) { const checkbox = todoElement.querySelector('input[type="checkbox"]'); if(checkbox) checkbox.checked = !isCompleted; // Revert state } } } // Delete a Todo Item async function deleteTodoItem(id) { errorMessage.textContent = ''; try { const response = await fetch(`/api/todos/${id}`, { method: 'DELETE', }); if (response.status === 401 || response.status === 403) { window.location.href = '/login'; return; } if (!response.ok && response.status !== 204) { // Allow 204 No Content const result = await response.json(); throw new Error(result.message || 'Fehler beim Löschen'); } // Remove the todo item from the DOM const todoElement = todoList.querySelector(`li[data-id="${id}"]`); if (todoElement) { todoElement.remove(); } } catch (error) { console.error('Error deleting todo:', error); errorMessage.textContent = `Fehler beim Löschen: ${error.message}`; } } // --- DOM Manipulation --- // Render the entire list of todos function renderTodoList(todos) { if (!todoList) return; todoList.innerHTML = ''; // Clear existing list if (todos.length === 0) { todoList.innerHTML = '
Noch keine Aufgaben vorhanden.
'; } else { todos.forEach(todo => addTodoToDOM(todo)); } } // Add a single todo item to the DOM function addTodoToDOM(todo) { if (!todoList) return; // Remove the "no tasks" message if it exists const noTasksMessage = todoList.querySelector('p'); if (noTasksMessage) { noTasksMessage.remove(); } const li = document.createElement('li'); li.classList.add('todo-item'); li.dataset.id = todo.id; // Store todo ID on the element if (todo.is_completed) { li.classList.add('completed'); } const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = todo.is_completed; const span = document.createElement('span'); span.textContent = todo.task; const deleteButton = document.createElement('button'); deleteButton.textContent = 'Löschen'; deleteButton.classList.add('btn-delete'); // Use specific class for deletion li.appendChild(checkbox); li.appendChild(span); li.appendChild(deleteButton); // Prepend to show newest todos first, or append for oldest first todoList.prepend(li); // Add new todos to the top } // --- Initial Load --- fetchTodos(); // Load todos when the page loads }