154 lines
4.1 KiB
JavaScript
154 lines
4.1 KiB
JavaScript
/**
|
|
* 🌐 MASTER 08: INTERAKTIVE TASK-APP (MUSTERLÖSUNG) 🌐
|
|
* ====================================================
|
|
*/
|
|
|
|
/**
|
|
* @typedef {'high' | 'medium' | 'low'} TaskPriority
|
|
* @typedef {'all' | 'active' | 'completed'} FilterStatus
|
|
*
|
|
* @typedef {Object} Task
|
|
* @property {number} id
|
|
* @property {string} title
|
|
* @property {TaskPriority} priority
|
|
* @property {boolean} completed
|
|
* @property {string | null} dueDate
|
|
* @property {string} createdAt
|
|
*
|
|
* @typedef {Object} TaskStatistics
|
|
* @property {number} total
|
|
* @property {number} active
|
|
* @property {number} completed
|
|
* @property {number} highPriorityCount
|
|
*/
|
|
|
|
class TaskManager {
|
|
constructor(initialTasks = []) {
|
|
/** @type {Task[]} */
|
|
this.tasks = [];
|
|
this.nextId = 1;
|
|
|
|
if (Array.isArray(initialTasks)) {
|
|
for (const t of initialTasks) {
|
|
if (t && typeof t === "object") {
|
|
const task = {
|
|
id: typeof t.id === "number" ? t.id : this.nextId++,
|
|
title: typeof t.title === "string" ? t.title.trim() : "Ohne Titel",
|
|
priority: ["high", "medium", "low"].includes(t.priority) ? t.priority : "medium",
|
|
completed: Boolean(t.completed),
|
|
dueDate: (typeof t.dueDate === "string" && t.dueDate.trim().length > 0) ? t.dueDate.trim() : null,
|
|
createdAt: t.createdAt || new Date().toISOString()
|
|
};
|
|
if (task.id >= this.nextId) {
|
|
this.nextId = task.id + 1;
|
|
}
|
|
this.tasks.push(task);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 🎯 TEILZIEL 1: addTask(title, priority = 'medium', dueDate = null)
|
|
*/
|
|
addTask(title, priority = "medium", dueDate = null) {
|
|
if (typeof title !== "string" || title.trim().length === 0) {
|
|
throw new Error("Aufgabentitel darf nicht leer sein");
|
|
}
|
|
|
|
const validPriority = ["high", "medium", "low"].includes(priority) ? priority : "medium";
|
|
const normalizedDueDate = (typeof dueDate === "string" && dueDate.trim().length > 0) ? dueDate.trim() : null;
|
|
|
|
const task = {
|
|
id: this.nextId++,
|
|
title: title.trim(),
|
|
priority: validPriority,
|
|
completed: false,
|
|
dueDate: normalizedDueDate,
|
|
createdAt: new Date().toISOString()
|
|
};
|
|
|
|
this.tasks.push(task);
|
|
return task;
|
|
}
|
|
|
|
/**
|
|
* 🎯 TEILZIEL 2: toggleTask(id)
|
|
*/
|
|
toggleTask(id) {
|
|
const numId = Number(id);
|
|
const task = this.tasks.find(t => t.id === numId);
|
|
if (!task) {
|
|
return null;
|
|
}
|
|
task.completed = !task.completed;
|
|
return task;
|
|
}
|
|
|
|
/**
|
|
* 🎯 TEILZIEL 3: deleteTask(id)
|
|
*/
|
|
deleteTask(id) {
|
|
const numId = Number(id);
|
|
const index = this.tasks.findIndex(t => t.id === numId);
|
|
if (index === -1) {
|
|
return false;
|
|
}
|
|
this.tasks.splice(index, 1);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 🎯 TEILZIEL 4: getFilteredTasks(filterStatus = 'all', searchQuery = '')
|
|
*/
|
|
getFilteredTasks(filterStatus = "all", searchQuery = "") {
|
|
let result = [...this.tasks];
|
|
|
|
if (filterStatus === "active") {
|
|
result = result.filter(t => !t.completed);
|
|
} else if (filterStatus === "completed") {
|
|
result = result.filter(t => t.completed);
|
|
}
|
|
|
|
if (typeof searchQuery === "string" && searchQuery.trim().length > 0) {
|
|
const query = searchQuery.trim().toLowerCase();
|
|
result = result.filter(t => t.title.toLowerCase().includes(query));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 🎯 TEILZIEL 5: getStatistics()
|
|
*/
|
|
getStatistics() {
|
|
const total = this.tasks.length;
|
|
const completed = this.tasks.filter(t => t.completed).length;
|
|
const active = total - completed;
|
|
const highPriorityCount = this.tasks.filter(t => t.priority === "high").length;
|
|
|
|
return {
|
|
total,
|
|
active,
|
|
completed,
|
|
highPriorityCount
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hilfsmethode: Task nach ID suchen
|
|
*/
|
|
getTaskById(id) {
|
|
const numId = Number(id);
|
|
return this.tasks.find(t => t.id === numId) || null;
|
|
}
|
|
|
|
/**
|
|
* Hilfsmethode: Alle erledigten Aufgaben auf einmal löschen
|
|
*/
|
|
clearCompleted() {
|
|
const initialCount = this.tasks.length;
|
|
this.tasks = this.tasks.filter(t => !t.completed);
|
|
return initialCount - this.tasks.length;
|
|
}
|
|
}
|