147 lines
6.6 KiB
HTML
147 lines
6.6 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html lang="en">
|
||
|
|
||
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
<link rel="stylesheet" type="text/css"
|
||
|
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" />
|
||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||
|
<title>Kanban Board</title>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<div class="container mt-4">
|
||
|
<h1>Kanban Board</h1>
|
||
|
<form action="/update-task-status" method="POST" class="my-4">
|
||
|
<div class="mb-3">
|
||
|
<label for="title" class="form-label">Task Title</label>
|
||
|
<input type="text" class="form-control" id="title" name="title" required>
|
||
|
</div>
|
||
|
<div class="mb-3">
|
||
|
<label for="description" class="form-label">Task Description</label>
|
||
|
<textarea class="form-control" id="description" name="description" required></textarea>
|
||
|
</div>
|
||
|
<div class="mb-3">
|
||
|
<label for="status" class="form-label">Status</label>
|
||
|
<select class="form-select" id="status" name="status" required>
|
||
|
<option value="todo">To Do</option>
|
||
|
<option value="in_progress">In Progress</option>
|
||
|
<option value="done">Done</option>
|
||
|
</select>
|
||
|
</div>
|
||
|
<input type="hidden" name="task_id" id="task_id">
|
||
|
<button type="submit" class="btn btn-primary" onclick="updateTaskStatus(event)">Add Task</button>
|
||
|
</form>
|
||
|
<h2>Tasks:</h2>
|
||
|
<div class="row">
|
||
|
<div class="col" id="todo">
|
||
|
<h3>To Do</h3>
|
||
|
<div class="sortable" data-status="todo">
|
||
|
{{ range .Tasks }}
|
||
|
{{ if eq .Status "todo" }}
|
||
|
<div class="card my-2" data-id="{{ .ID }}">
|
||
|
<div class="card-body">
|
||
|
<h5 class="card-title">{{ .Title }}</h5>
|
||
|
<p class="card-text">{{ .Description }}</p>
|
||
|
<p class="card-text"><strong>Status:</strong> {{ .Status }}</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
{{ end }}
|
||
|
{{ end }}
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="col" id="in-progress">
|
||
|
<h3>In Progress</h3>
|
||
|
<div class="sortable" data-status="in_progress">
|
||
|
{{ range .Tasks }}
|
||
|
{{ if eq .Status "in_progress" }}
|
||
|
<div class="card my-2" data-id="{{ .ID }}">
|
||
|
<div class="card-body">
|
||
|
<h5 class="card-title">{{ .Title }}</h5>
|
||
|
<p class="card-text">{{ .Description }}</p>
|
||
|
<p class="card-text"><strong>Status:</strong> {{ .Status }}</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
{{ end }}
|
||
|
{{ end }}
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="col" id="done">
|
||
|
<h3>Done</h3>
|
||
|
<div class="sortable" data-status="done">
|
||
|
{{ range .Tasks }}
|
||
|
{{ if eq .Status "done" }}
|
||
|
<div class="card my-2" data-id="{{ .ID }}">
|
||
|
<div class="card-body">
|
||
|
<h5 class="card-title">{{ .Title }}</h5>
|
||
|
<p class="card-text">{{ .Description }}</p>
|
||
|
<p class="card-text"><strong>Status:</strong> {{ .Status }}</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
{{ end }}
|
||
|
{{ end }}
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.13.0/Sortable.min.js"></script>
|
||
|
<script>
|
||
|
function updateTaskStatus(event) {
|
||
|
event.preventDefault();
|
||
|
var form = event.target.closest('form');
|
||
|
var taskId = form.querySelector('#task_id').value;
|
||
|
var newStatus = form.querySelector('#status').value;
|
||
|
fetch(form.action, {
|
||
|
method: 'POST',
|
||
|
headers: {
|
||
|
'Content-Type': 'application/json'
|
||
|
},
|
||
|
body: JSON.stringify({ id: taskId, status: newStatus })
|
||
|
}).then(function () {
|
||
|
// Update the task status in the card
|
||
|
var card = form.closest('.card');
|
||
|
card.querySelector('.card-text:last-child').innerHTML = '<strong>Status:</strong> ' + newStatus;
|
||
|
}).catch(function (error) {
|
||
|
console.error('Error:', error);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
document.addEventListener('DOMContentLoaded', function () {
|
||
|
var sortableContainers = [].slice.call(document.querySelectorAll('.sortable'));
|
||
|
sortableContainers.forEach(function (container) {
|
||
|
new Sortable(container, {
|
||
|
group: 'kanban',
|
||
|
draggable: '.card',
|
||
|
animation: 150,
|
||
|
handle: '.card',
|
||
|
onEnd: function (evt) {
|
||
|
var taskId = evt.item.getAttribute('data-id');
|
||
|
var newStatus = evt.to.getAttribute('data-status');
|
||
|
|
||
|
// Update the task status in the backend
|
||
|
fetch('/update-task-status', {
|
||
|
method: 'POST',
|
||
|
headers: {
|
||
|
'Content-Type': 'application/json'
|
||
|
},
|
||
|
body: JSON.stringify({ id: taskId, status: newStatus })
|
||
|
}).then(function (response) {
|
||
|
if (response.ok) {
|
||
|
// Update the task status in the card
|
||
|
evt.item.querySelector('.card-text:last-child').innerHTML = '<strong>Status:</strong> ' + newStatus;
|
||
|
} else {
|
||
|
console.error('Failed to update task status:', response.status);
|
||
|
}
|
||
|
}).catch(function (error) {
|
||
|
console.error('Error:', error);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
</script>
|
||
|
</body>
|
||
|
|
||
|
</html>
|