// Initial data structure with enhanced features const todos = [ { id: 1, text: 'Beispielaufgabe erstellen', completed: true, priority: 'medium', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }, { id: 2, text: 'Todo-App mit neuen Features verbessern', completed: false, priority: 'high', dueDate: new Date(Date.now() + 86400000).toISOString().split('T')[0], // Morgen createdAt: new Date(Date.now() - 86400000).toISOString(), updatedAt: new Date(Date.now() - 86400000).toISOString() }, { id: 3, text: 'Dokumentation für das Team erstellen', completed: false, priority: 'low', createdAt: new Date(Date.now() - 172800000).toISOString(), // Vorgestern updatedAt: new Date(Date.now() - 172800000).toISOString() } ]; function todoApp() { return { todos: [], newTodo: '', newPriority: 'medium', newDueDate: '', filter: 'all', sortBy: 'priority', searchQuery: '', showToast: false, toastMessage: '', toastType: 'success', editingId: null, editingText: '', editingPriority: 'medium', editingDueDate: '', dragStartIndex: null, dragOverIndex: null, // Initialize from localStorage or default init() { const savedTodos = localStorage.getItem('todos'); this.todos = savedTodos ? JSON.parse(savedTodos) : todos; this.updateLocalStorage(); // Initialize Feather icons after content loads setTimeout(() => { if (typeof feather !== 'undefined') { feather.replace(); } }, 100); }, // Filtered and sorted todos based on current settings get filteredTodos() { let filtered = this.todos; // Apply search filter if (this.searchQuery.trim() !== '') { const query = this.searchQuery.toLowerCase(); filtered = filtered.filter(todo => todo.text.toLowerCase().includes(query) ); } // Apply status filter if (this.filter === 'active') { filtered = filtered.filter(todo => !todo.completed); } else if (this.filter === 'completed') { filtered = filtered.filter(todo => todo.completed); } // Apply sorting filtered = [...filtered]; // Create a copy if (this.sortBy === 'priority') { const priorityOrder = { high: 0, medium: 1, low: 2, undefined: 3 }; filtered.sort((a, b) => { const aPriority = priorityOrder[a.priority || 'undefined']; const bPriority = priorityOrder[b.priority || 'undefined']; return aPriority - bPriority; }); } else { filtered.sort((a, b) => { const aDate = new Date(a.createdAt); const bDate = new Date(b.createdAt); return bDate - aDate; // Newest first }); } return filtered; }, // Enhanced statistics get completedCount() { return this.todos.filter(todo => todo.completed).length; }, get activeCount() { return this.todos.filter(todo => !todo.completed).length; }, get totalCount() { return this.todos.length; }, get overdueCount() { const today = new Date().toISOString().split('T')[0]; return this.todos.filter(todo => !todo.completed && todo.dueDate && todo.dueDate < today ).length; }, // Check if a todo is overdue isOverdue(dueDate) { if (!dueDate) return false; const today = new Date().toISOString().split('T')[0]; return dueDate < today; }, // Add new todo with enhanced features addTodo() { if (this.newTodo.trim() === '') { this.showNotification('Bitte gib eine Aufgabe ein', 'error'); return; } const newTodo = { id: Date.now(), text: this.newTodo.trim(), completed: false, priority: this.newPriority, dueDate: this.newDueDate || null, overdue: this.isOverdue(this.newDueDate), createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; this.todos.unshift(newTodo); this.newTodo = ''; this.newDueDate = ''; this.newPriority = 'medium'; this.updateLocalStorage(); this.showNotification('Aufgabe hinzugefügt', 'success'); }, // Toggle todo completion toggleTodo(id) { const todo = this.todos.find(t => t.id === id); if (todo) { todo.completed = !todo.completed; todo.updatedAt = new Date().toISOString(); this.updateLocalStorage(); const message = todo.completed ? 'Aufgabe erledigt!' : 'Aufgabe wieder geöffnet'; this.showNotification(message, 'success'); } }, // Delete todo deleteTodo(id) { this.todos = this.todos.filter(t => t.id !== id); this.updateLocalStorage(); this.showNotification('Aufgabe gelöscht', 'success'); }, // Clear completed todos clearCompleted() { const completedCount = this.completedCount; this.todos = this.todos.filter(t => !t.completed); this.updateLocalStorage(); this.showNotification(`${completedCount} erledigte Aufgabe(n) gelöscht`, 'success'); }, // Edit todo with enhanced features startEdit(id, text, priority = 'medium', dueDate = '') { this.editingId = id; this.editingText = text; this.editingPriority = priority || 'medium'; this.editingDueDate = dueDate || ''; }, saveEdit() { if (this.editingText.trim() === '') { this.showNotification('Aufgabe darf nicht leer sein', 'error'); return; } const todo = this.todos.find(t => t.id === this.editingId); if (todo) { todo.text = this.editingText.trim(); todo.priority = this.editingPriority; todo.dueDate = this.editingDueDate || null; todo.overdue = this.isOverdue(this.editingDueDate); todo.updatedAt = new Date().toISOString(); this.updateLocalStorage(); this.cancelEdit(); this.showNotification('Aufgabe aktualisiert', 'success'); } }, cancelEdit() { this.editingId = null; this.editingText = ''; this.editingPriority = 'medium'; this.editingDueDate = ''; }, // Drag and drop functionality dragStart(index) { this.dragStartIndex = index; this.dragOverIndex = null; }, dragOver(event) { event.preventDefault(); }, setDragOver(index) { if (index !== this.dragStartIndex) { this.dragOverIndex = index; } }, clearDragOver() { this.dragOverIndex = null; }, dropOn(targetIndex) { if (this.dragStartIndex === null || this.dragStartIndex === targetIndex) { this.clearDragOver(); return; } const draggedTodo = this.todos[this.dragStartIndex]; this.todos.splice(this.dragStartIndex, 1); this.todos.splice(targetIndex, 0, draggedTodo); this.dragStartIndex = null; this.dragOverIndex = null; this.updateLocalStorage(); this.showNotification('Aufgabe verschoben', 'success'); }, drop() { this.dragStartIndex = null; this.dragOverIndex = null; }, // Format date for display formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); }, // Format due date formatDueDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); const today = new Date(); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); if (date.toDateString() === today.toDateString()) { return 'Heute'; } else if (date.toDateString() === tomorrow.toDateString()) { return 'Morgen'; } else { return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); } }, // Show notification toast showNotification(message, type = 'success') { this.toastMessage = message; this.toastType = type; this.showToast = true; setTimeout(() => { this.showToast = false; }, 3000); }, // Update localStorage updateLocalStorage() { localStorage.setItem('todos', JSON.stringify(this.todos)); }, // Update Feather icons when needed updateIcons() { if (typeof feather !== 'undefined') { feather.replace(); } } }; }