├── README.md ├── 3 dots.jpg ├── delete.png ├── script.js ├── LICENSE ├── index.html ├── tasks.js ├── todo.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # -JS-best-practices-code-review -------------------------------------------------------------------------------- /3 dots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hafiz1379/-JS-best-practices-code-review/HEAD/3 dots.jpg -------------------------------------------------------------------------------- /delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hafiz1379/-JS-best-practices-code-review/HEAD/delete.png -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | 2 | function addNewTask() { 3 | const description = addInput.value; 4 | if (description) { 5 | Task.addTask(description); 6 | addInput.value = ''; 7 | renderTasks(); 8 | } 9 | } 10 | renderTasks(); 11 | addButton.addEventListener('click', () => { 12 | addNewTask(); 13 | }); 14 | addInput.addEventListener('keypress', (event) => { 15 | if (event.key === 'Enter') { 16 | addNewTask(); 17 | } 18 | }); 19 | clearAllButton.addEventListener('click', () => { 20 | Task.clearAllTasks(); 21 | renderTasks(); 22 | }); 23 | 24 | clearAllButton.addEventListener('click', () => { 25 | const tasks = Task.getTasks(); 26 | const newTasks = tasks.filter((task) => !task.completed); 27 | newTasks.forEach((task, index) => { 28 | task.id = index + 1; 29 | }); 30 | // Remove the event listener to avoid potential memory leaks 31 | clearAllButton.removeEventListener('click', clearAllButtonClickHandler); 32 | renderTasks(); 33 | }); 34 | 35 | 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Hafiz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | to do list 8 | 14 | 15 | 16 |
17 |

To Do list

18 |
19 | 24 | 27 |
28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tasks.js: -------------------------------------------------------------------------------- 1 | class Task { 2 | static getTasks() { 3 | const tasks = localStorage.getItem('tasks'); 4 | return tasks ? JSON.parse(tasks) : []; 5 | } 6 | 7 | static setTasks(tasks) { 8 | localStorage.setItem('tasks', JSON.stringify(tasks)); 9 | } 10 | 11 | static addTask(description) { 12 | const tasks = Task.getTasks(); 13 | const task = { 14 | id: tasks.length + 1, 15 | description, 16 | completed: false, 17 | }; 18 | tasks.push(task); 19 | Task.setTasks(tasks); 20 | return task; 21 | } 22 | 23 | static removeTask(id) { 24 | const tasks = Task.getTasks(); 25 | const index = tasks.findIndex((task) => task.id === id); 26 | if (index !== -1) { 27 | tasks.splice(index, 1); 28 | for (let i = index; i < tasks.length; i += 1) { 29 | tasks[i].id -= 1; 30 | } 31 | Task.setTasks(tasks); 32 | } 33 | } 34 | 35 | static editTaskDescription(id, newDescription) { 36 | const tasks = Task.getTasks(); 37 | const task = tasks.find((task) => task.id === id); 38 | task.description = newDescription; 39 | Task.setTasks(tasks); 40 | } 41 | 42 | static toggleTaskStatus(id) { 43 | const tasks = Task.getTasks(); 44 | tasks.forEach((task) => { 45 | if (task.id === id) { 46 | task.completed = !task.completed; 47 | } 48 | }); 49 | Task.setTasks(tasks); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /todo.js: -------------------------------------------------------------------------------- 1 | const $ = document; 2 | 3 | const todoList = $.querySelector('.todo-list'); 4 | const addInput = $.querySelector('.add-input'); 5 | const addButton = $.querySelector('.add-button'); 6 | const clearAllButton = $.querySelector('.clear-all'); 7 | 8 | function renderTasks() { 9 | const tasks = Task.getTasks(); 10 | todoList.innerHTML = ''; 11 | tasks.forEach((task) => { 12 | const li = $.createElement('li'); 13 | li.className = 'todo-item'; 14 | li.innerHTML = ` 15 | 19 | 20 | `; 21 | const editInput = li.querySelector('.todo-item-edit'); 22 | editInput.addEventListener('blur', () => { 23 | const newDescription = editInput.value; 24 | Task.editTaskDescription(task.id, newDescription); 25 | renderTasks(); 26 | }); 27 | 28 | const checkbox = li.querySelector('.todo-item-check'); 29 | checkbox.addEventListener('change', () => { 30 | Task.toggleTaskStatus(task.id); 31 | renderTasks(); 32 | }); 33 | 34 | const deleteIcon = li.querySelector('.icon'); 35 | deleteIcon.addEventListener('click', () => { 36 | Task.removeTask(task.id); 37 | renderTasks(); 38 | }); 39 | todoList.appendChild(li); 40 | }); 41 | } 42 | 43 | renderTasks(); 44 | 45 | addButton.addEventListener('click', () => { 46 | const description = addInput.value; 47 | if (description) { 48 | Task.addTask(description); 49 | addInput.value = ''; 50 | renderTasks(); 51 | } 52 | }); 53 | 54 | addInput.addEventListener('keypress', (event) => { 55 | if (event.key === 'Enter') { 56 | const description = addInput.value; 57 | if (description) { 58 | Task.addTask(description); 59 | addInput.value = ''; 60 | renderTasks(); 61 | } 62 | } 63 | }); 64 | 65 | clearAllButton.addEventListener('click', () => { 66 | const tasks = Task.getTasks(); 67 | const newTasks = tasks.filter((task) => !task.completed); 68 | newTasks.forEach((task, index) => { 69 | task.id = index + 1; 70 | }); 71 | 72 | Task.setTasks(newTasks); 73 | renderTasks(); 74 | }); 75 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-color: #e8e8e8; 9 | } 10 | 11 | .container { 12 | background-color: #fff; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | width: 80%; 17 | margin-top: 8rem; 18 | border: 1px solid #060607c7; 19 | margin-left: 10%; 20 | box-sizing: border-box; 21 | padding: 9px; 22 | border-radius: 10px; 23 | } 24 | 25 | .container h2 { 26 | align-self: center; 27 | margin-bottom: 7px; 28 | } 29 | 30 | #todo-list { 31 | width: 400px; 32 | margin: 0 auto; 33 | } 34 | 35 | ul { 36 | list-style: none; 37 | padding: 0; 38 | width: 100%; 39 | margin: 0; 40 | } 41 | 42 | li { 43 | padding: 2% 0; 44 | border-top: 2px solid lightgray; 45 | width: 100%; 46 | display: flex; 47 | justify-content: space-between; 48 | } 49 | 50 | .input-container { 51 | display: flex; 52 | width: 100%; 53 | justify-content: center; 54 | } 55 | 56 | input { 57 | border: 1px solid transparent; 58 | } 59 | 60 | .add-input { 61 | width: 100%; 62 | height: 30px; 63 | padding: 5px; 64 | } 65 | 66 | .add-button { 67 | background: transparent; 68 | border: transparent; 69 | margin-left: 5px; 70 | } 71 | 72 | .clear-all { 73 | width: 100%; 74 | height: 43px; 75 | border-radius: 0 0 42px 40px; 76 | padding: 5px; 77 | border: transparent; 78 | background: #ededed4c; 79 | cursor: pointer; 80 | } 81 | 82 | .task { 83 | font-size: 20px; 84 | padding: 10px; 85 | border-bottom: 1px solid #ccc; 86 | } 87 | 88 | .todo-completed .todo-item-edit { 89 | text-decoration: line-through; 90 | color: #ccc; 91 | } 92 | 93 | .icon { 94 | width: 17px; 95 | background: url(./3\ dots.jpg); 96 | background-position: center; 97 | background-size: contain; 98 | background-repeat: no-repeat; 99 | cursor: pointer; 100 | } 101 | 102 | .icon:hover { 103 | background: url(./delete.png); 104 | width: 15px; 105 | background-position: center; 106 | background-repeat: no-repeat; 107 | background-size: contain; 108 | } 109 | --------------------------------------------------------------------------------