From d0798f8e248141d2fbeae78b18d73eaca95b7e76 Mon Sep 17 00:00:00 2001 From: bochard Date: Fri, 30 May 2025 21:16:04 +0800 Subject: [PATCH] added a delete task feature --- Classes/Tasks.php | 9 ++++- TODO.TXT | 3 +- includes/dashboard.php | 25 ++++++++++-- includes/delete_task.php | 35 +++++++++++++++- js/tasks.js | 86 +++++++++++++++++++++++++++++++++++----- 5 files changed, 140 insertions(+), 18 deletions(-) diff --git a/Classes/Tasks.php b/Classes/Tasks.php index 867a06d..5280b5a 100644 --- a/Classes/Tasks.php +++ b/Classes/Tasks.php @@ -27,10 +27,17 @@ class Tasks extends DbConn { } public function addTask($pdo, $userId, $task){ - $query = 'INSERT INTO tasks (task, user_id) VALUES (:task, :userId)'; + $query = 'INSERT INTO tasks (task, user_id) VALUES (:task, :userId);'; $stmt = $pdo->prepare($query); $stmt->bindParam(':task', $task); $stmt->bindParam(':userId', $userId); $stmt->execute(); } + + public function deleteTask($pdo, $taskId){ + $query = 'DELETE FROM tasks WHERE task_id = :taskId;'; + $stmt = $pdo->prepare($query); + $stmt->bindParam(':taskId', $taskId); + $stmt->execute(); + } } \ No newline at end of file diff --git a/TODO.TXT b/TODO.TXT index 9ff158d..b517d73 100644 --- a/TODO.TXT +++ b/TODO.TXT @@ -1,8 +1,7 @@ 1. encrypt passwords on signup 2. add a session timer when user logged in 3. don't give direct access to paths esp. when usr. is not logged in or that path must not be accessible -4. add a short animation loading progress bar when user did some actions to a task -5. create 'deleting task' feature +4. add a short animation loading progress bar when user did some actions to a task 6. create 'editing task' feature 7. create 'task sorting' feature 8. create 'task search' feature \ No newline at end of file diff --git a/includes/dashboard.php b/includes/dashboard.php index 72ca48b..0b013c1 100644 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -32,6 +32,19 @@ transition-duration: 0.2s; transition-property: visibility, opacity; } + .table-container { + overflow: hidden; + overflow-y: scroll; + height: 200px; + } + thead { + top: 0; + z-index: 2; + position: sticky; + } + table { + width: 290px; + } @@ -56,13 +69,17 @@ -
+
+ + +
+ +
- - - + + diff --git a/includes/delete_task.php b/includes/delete_task.php index e1898f3..d4eced7 100644 --- a/includes/delete_task.php +++ b/includes/delete_task.php @@ -10,5 +10,38 @@ require_once __DIR__ . '/../Classes/Tasks.php'; header('Content-Type: application/json'); if($_SERVER['REQUEST_METHOD'] === 'POST'){ - // will add here soon... + $taskIds = json_decode(file_get_contents('php://input'), true); + + try{ + $dbconn = new DbConn(); + $pdo = $dbconn->getPdo(); + + $userId = $_SESSION['user_data']['user_id']; + $tasks = new Tasks($pdo, $userId); + $error = $tasks->error; + + foreach($taskIds as $taskId){ + $tasks->isInputEmpty($taskId); + if(empty($error)){ + $tasks->deleteTask($pdo, $taskId); + } + } + + if(empty($error)){ + $response = [ + 'status' => 'success', + 'message' => 'Task deleted successfully!', + ]; + } else{ + $response = [ + 'status' => 'failed', + 'message' => 'Failed to delete task.', + ]; + } + + echo json_encode($response); + + } catch(PDOException $e){ + die("Query failed: {$e}"); + } } \ No newline at end of file diff --git a/js/tasks.js b/js/tasks.js index 59c85e0..f60b14f 100644 --- a/js/tasks.js +++ b/js/tasks.js @@ -16,14 +16,16 @@ function loadTasks(){ // fetching tasks on database const tr = document.createElement('tr'); tr.innerHTML = ` - `; tbody.appendChild(tr); + + // listen for checkboxes after loading tasks in DOM + addCheckboxListeners(); }); } else{ const tr = document.createElement('tr'); @@ -36,6 +38,34 @@ function loadTasks(){ // fetching tasks on database }); } +function addCheckboxListeners(){ + const checkboxes = document.querySelectorAll('#task-body input[type="checkbox"]'); + + checkboxes.forEach(function(checkbox){ + checkbox.addEventListener('change', function(){ + const isAnyChecked = Array.from(checkboxes).some(function(checkbox){ + return checkbox.checked; + }); + + if(isAnyChecked){ + removeDisabledAttributes(); + } else{ + setDisabledAttributes(); + } + }); + }); +} + +function removeDisabledAttributes(){ + document.getElementById('edit-task').removeAttribute('disabled'); + document.getElementById('delete-task').removeAttribute('disabled'); +}; + +function setDisabledAttributes(){ + document.getElementById('edit-task').setAttribute('disabled', true); + document.getElementById('delete-task').setAttribute('disabled', true); +}; + function addTask(){ // adding task on database const taskInput = document.getElementById('task-name'); const formData = new FormData(addTaskForm); @@ -59,16 +89,48 @@ function addTask(){ // adding task on database console.log('Response from server:', data); console.log('Status:', data.status); console.log('Message:', data.message); + setTimeout(function(){ + loadTasks(); + }, 500); + setDisabledAttributes(); + popupNewTaskClose(); }) - .catch(function(err){ - console.error(err); + .catch(function(error){ + console.error(error); }); - - setTimeout(function(){ +} + +function deleteTask(){ + const checkboxes = document.querySelectorAll('#task-body input[type="checkbox"]'); + let isCheckedArray = []; + + for(let checkbox of checkboxes){ + if(checkbox.checked){ + isCheckedArray.push(checkbox.id); + } + } + + // after iterating and finding the id of a checkbox that is checked... + fetch('./includes/delete_task.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(isCheckedArray) + }) + .then(function(response){ + return response.json(); + }) + .then(function(data){ + console.log('Response from server:', data); + console.log('Status:', data.status); + console.log('Message:', data.message); + setTimeout(function(){ loadTasks(); - }, 500); - - popupNewTaskClose(); + }, 500); + setDisabledAttributes(); + }) + .catch(function(error){ + console.error(error); + }); } function resetTaskInputPlaceholder(){ @@ -110,6 +172,10 @@ document.getElementById('add-task-form').addEventListener('submit', function(e){ addTask(); }); +document.getElementById('delete-task').addEventListener('click', function(e){ + e.preventDefault(); + deleteTask(); +}); // calls loadTasks(); \ No newline at end of file -- 2.39.5
taskcreated dateTask
- - + + ${task.task}${task.created_datetime}