From c80b5da4a44c1b45872e0f228af4df44f11855d6 Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 08:37:43 +0100 Subject: [PATCH 1/9] add delete button and styles --- Sprint-3/todo-list/index.html | 4 ++++ Sprint-3/todo-list/style.css | 22 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Sprint-3/todo-list/index.html b/Sprint-3/todo-list/index.html index 4d12c4654..b1145c3e5 100644 --- a/Sprint-3/todo-list/index.html +++ b/Sprint-3/todo-list/index.html @@ -18,6 +18,10 @@

My ToDo List

+
+ +
+ diff --git a/Sprint-3/todo-list/style.css b/Sprint-3/todo-list/style.css index 535e91227..592132c80 100644 --- a/Sprint-3/todo-list/style.css +++ b/Sprint-3/todo-list/style.css @@ -41,7 +41,7 @@ h1 { .todo-input button { padding: 10px 20px; font-size: 16px; - background-color: #4CAF50; + background-color: #4caf50; color: white; border: none; border-radius: 6px; @@ -68,6 +68,26 @@ h1 { background-color: #fff; } +.todo-delete { + display: flex; + justify-content: flex-end; +} + +#delete-completed-btn { + padding: 10px 20px; + margin-bottom: 10px; + font-size: 16px; + background-color: #aa0000; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; +} + +#delete-completed-btn:hover { + background-color: #d10000; +} + .description { flex: 1; margin-right: 10px; From 59f6c3dffbf778897ded31cbbb69f8c40469c8b1 Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 08:44:28 +0100 Subject: [PATCH 2/9] add deleteCompleted function --- Sprint-3/todo-list/todos.mjs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Sprint-3/todo-list/todos.mjs b/Sprint-3/todo-list/todos.mjs index f17ab6a25..18b556777 100644 --- a/Sprint-3/todo-list/todos.mjs +++ b/Sprint-3/todo-list/todos.mjs @@ -26,4 +26,14 @@ export function toggleCompletedOnTask(todos, taskIndex) { if (todos[taskIndex]) { todos[taskIndex].completed = !todos[taskIndex].completed; } -} \ No newline at end of file +} + +// Delete all completed todos from todos[] +export function deleteCompleted(todos) { + for (let i = todos.length - 1; i >= 0; i--) { + if (todos[i].completed) { + deleteTask(todos, i); + } + } + return todos; +} From 65d7d9effff79c946d1876800fdf94d0f8f725d1 Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 08:52:41 +0100 Subject: [PATCH 3/9] add deleteCompleted tests --- Sprint-3/todo-list/todos.test.mjs | 55 +++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/Sprint-3/todo-list/todos.test.mjs b/Sprint-3/todo-list/todos.test.mjs index bae7ae491..0ab2c2d23 100644 --- a/Sprint-3/todo-list/todos.test.mjs +++ b/Sprint-3/todo-list/todos.test.mjs @@ -13,7 +13,7 @@ function createMockTodos() { { task: "Task 1 description", completed: true }, { task: "Task 2 description", completed: false }, { task: "Task 3 description", completed: true }, - { task: "Task 4 description", completed: false }, + { task: "Task 4 description", completed: false }, ]; } @@ -29,7 +29,6 @@ describe("addTask()", () => { }); test("Should append a new task to the end of a ToDo list", () => { - const todos = createMockTodos(); const lengthBeforeAddition = todos.length; Todos.addTask(todos, theTask.task, theTask.completed); @@ -42,7 +41,6 @@ describe("addTask()", () => { }); describe("deleteTask()", () => { - test("Delete the first task", () => { const todos = createMockTodos(); const todosBeforeDeletion = createMockTodos(); @@ -53,7 +51,7 @@ describe("deleteTask()", () => { expect(todos[0]).toEqual(todosBeforeDeletion[1]); expect(todos[1]).toEqual(todosBeforeDeletion[2]); - expect(todos[2]).toEqual(todosBeforeDeletion[3]); + expect(todos[2]).toEqual(todosBeforeDeletion[3]); }); test("Delete the second task (a middle task)", () => { @@ -66,7 +64,7 @@ describe("deleteTask()", () => { expect(todos[0]).toEqual(todosBeforeDeletion[0]); expect(todos[1]).toEqual(todosBeforeDeletion[2]); - expect(todos[2]).toEqual(todosBeforeDeletion[3]); + expect(todos[2]).toEqual(todosBeforeDeletion[3]); }); test("Delete the last task", () => { @@ -79,7 +77,7 @@ describe("deleteTask()", () => { expect(todos[0]).toEqual(todosBeforeDeletion[0]); expect(todos[1]).toEqual(todosBeforeDeletion[1]); - expect(todos[2]).toEqual(todosBeforeDeletion[2]); + expect(todos[2]).toEqual(todosBeforeDeletion[2]); }); test("Delete a non-existing task", () => { @@ -94,7 +92,6 @@ describe("deleteTask()", () => { }); describe("toggleCompletedOnTask()", () => { - test("Expect the 'completed' property to toggle on an existing task", () => { const todos = createMockTodos(); const taskIndex = 1; @@ -111,13 +108,12 @@ describe("toggleCompletedOnTask()", () => { const todos = createMockTodos(); const todosBeforeToggle = createMockTodos(); Todos.toggleCompletedOnTask(todos, 1); - - expect(todos[0]).toEqual(todosBeforeToggle[0]); + + expect(todos[0]).toEqual(todosBeforeToggle[0]); expect(todos[2]).toEqual(todosBeforeToggle[2]); expect(todos[3]).toEqual(todosBeforeToggle[3]); }); - test("Expect no change when toggling on a non-existing task", () => { const todos = createMockTodos(); const todosBeforeToggle = createMockTodos(); @@ -130,3 +126,42 @@ describe("toggleCompletedOnTask()", () => { }); }); +// tests for deleteCompleted +describe("deleteCompleted()", () => { + test("Delete all completed todos from todos[]", () => { + const todos = createMockTodos(); + const todosBeforeDeletion = createMockTodos(); + Todos.deleteCompleted(todos); + + expect(todos).toHaveLength(2); + + // expect the first task in the new todo list to be the second task from the original list + expect(todos[0]).toEqual(todosBeforeDeletion[1]); + + // expect the second task in the new todo list to be the third task from the original list + expect(todos[1]).toEqual(todosBeforeDeletion[3]); + }); + + test("Delete all completed todos from todos[] when all todos are completed", () => { + const todos = createMockTodos().map((task) => ({ + ...task, + completed: true, + })); + const todosBeforeDeletion = createMockTodos(); + Todos.deleteCompleted(todos); + + expect(todos).toHaveLength(0); + }); + + test("Delete all completed todos from todos[] when no todos are completed", () => { + const todos = createMockTodos().map((task) => ({ + ...task, + completed: false, + })); + const initialLength = todos.length; + const todosBeforeDeletion = createMockTodos(); + Todos.deleteCompleted(todos); + + expect(todos).toHaveLength(initialLength); + }); +}); From c28529e15259e8878d3980a53cf454c0c789ec6a Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 08:52:56 +0100 Subject: [PATCH 4/9] add event listener for deleteCompleted --- Sprint-3/todo-list/script.mjs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Sprint-3/todo-list/script.mjs b/Sprint-3/todo-list/script.mjs index ba0b2ceae..2d92b7c31 100644 --- a/Sprint-3/todo-list/script.mjs +++ b/Sprint-3/todo-list/script.mjs @@ -1,4 +1,4 @@ -// Store everything imported from './todos.mjs' module as properties of an object named Todos +// Store everything imported from './todos.mjs' module as properties of an object named Todos import * as Todos from "./todos.mjs"; // To store the todo tasks @@ -9,14 +9,23 @@ window.addEventListener("load", () => { document.getElementById("add-task-btn").addEventListener("click", addNewTodo); // Populate sample data - Todos.addTask(todos, "Wash the dishes", false); + Todos.addTask(todos, "Wash the dishes", false); Todos.addTask(todos, "Do the shopping", true); render(); }); +// Delete completed tasks +document + .getElementById("delete-completed-btn") + .addEventListener("click", deleteCompletedTodos); -// A callback that reads the task description from an input field and +function deleteCompletedTodos() { + Todos.deleteCompleted(todos); + render(); +} + +// A callback that reads the task description from an input field and // append a new task to the todo list. function addNewTodo() { const taskInput = document.getElementById("new-task-input"); @@ -45,12 +54,11 @@ function render() { }); } - // Note: // - First child of #todo-item-template is a
  • element. // We will create each ToDo list item as a clone of this node. // - This variable is declared here to be close to the only function that uses it. -const todoListItemTemplate = +const todoListItemTemplate = document.getElementById("todo-item-template").content.firstElementChild; // Create a
  • element for the given todo task @@ -62,15 +70,15 @@ function createListItem(todo, index) { li.classList.add("completed"); } - li.querySelector('.complete-btn').addEventListener("click", () => { + li.querySelector(".complete-btn").addEventListener("click", () => { Todos.toggleCompletedOnTask(todos, index); render(); }); - - li.querySelector('.delete-btn').addEventListener("click", () => { + + li.querySelector(".delete-btn").addEventListener("click", () => { Todos.deleteTask(todos, index); render(); }); return li; -} \ No newline at end of file +} From fa5a54c2373ce1236229436f9d683ad73854183e Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 17:25:18 +0100 Subject: [PATCH 5/9] add deadline functionality and tests --- Sprint-3/todo-list/todos.mjs | 8 ++++++-- Sprint-3/todo-list/todos.test.mjs | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Sprint-3/todo-list/todos.mjs b/Sprint-3/todo-list/todos.mjs index 18b556777..a48b328ab 100644 --- a/Sprint-3/todo-list/todos.mjs +++ b/Sprint-3/todo-list/todos.mjs @@ -10,8 +10,12 @@ */ // Append a new task to todos[] -export function addTask(todos, task, completed = false) { - todos.push({ task, completed }); +export function addTask(todos, task, completed = false, deadline = null) { + const todo = { task, completed }; + if (deadline) { + todo.deadline = deadline; + } + todos.push(todo); } // Delete todos[taskIndex] if it exists diff --git a/Sprint-3/todo-list/todos.test.mjs b/Sprint-3/todo-list/todos.test.mjs index 0ab2c2d23..4e77f1c90 100644 --- a/Sprint-3/todo-list/todos.test.mjs +++ b/Sprint-3/todo-list/todos.test.mjs @@ -38,6 +38,27 @@ describe("addTask()", () => { // New task should be appended to the todos expect(todos[todos.length - 1]).toEqual(theTask); }); + + test("Should store deadline information if provided", () => { + let todos = []; + Todos.addTask(todos, "Task with deadline", false, "2026-07-31"); + expect(todos).toHaveLength(1); + expect(todos[0]).toEqual({ + task: "Task with deadline", + completed: false, + deadline: "2026-07-31" + }); + }); + + test("Should not store deadline if none is provided", () => { + let todos = []; + Todos.addTask(todos, "Task without deadline", false); + expect(todos).toHaveLength(1); + expect(todos[0]).toEqual({ + task: "Task without deadline", + completed: false + }); + }); }); describe("deleteTask()", () => { From 325d28cb700e23b9d2317fc8658e6ad6aadb4902 Mon Sep 17 00:00:00 2001 From: Tomislav Dukez Date: Fri, 24 Jul 2026 17:27:49 +0100 Subject: [PATCH 6/9] add deadline input and template elements and styles --- Sprint-3/todo-list/index.html | 8 ++++-- Sprint-3/todo-list/style.css | 46 +++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/Sprint-3/todo-list/index.html b/Sprint-3/todo-list/index.html index b1145c3e5..4bd11386f 100644 --- a/Sprint-3/todo-list/index.html +++ b/Sprint-3/todo-list/index.html @@ -14,7 +14,8 @@

    My ToDo List

    - + +
    @@ -31,7 +32,10 @@

    My ToDo List

    -->