botui/ui/suite/tasks/tasks.js
Rodrigo Rodriguez (Pragmatismo) 1f95ac7a15 refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00

226 lines
7.2 KiB
JavaScript

/* Tasks page JavaScript */
// Set active tab
function setActiveTab(button) {
document.querySelectorAll(".filter-tab").forEach((tab) => {
tab.classList.remove("active");
});
button.classList.add("active");
}
// Export tasks as JSON
function exportTasks() {
fetch("/api/tasks?format=json")
.then((response) => response.json())
.then((tasks) => {
const dataStr = JSON.stringify(tasks, null, 2);
const dataUri =
"data:application/json;charset=utf-8," +
encodeURIComponent(dataStr);
const exportFileDefaultName = `tasks-${new Date().toISOString().split("T")[0]}.json`;
const linkElement = document.createElement("a");
linkElement.setAttribute("href", dataUri);
linkElement.setAttribute("download", exportFileDefaultName);
linkElement.click();
});
}
// Update task statistics
function updateStats() {
fetch("/api/tasks/stats")
.then((response) => response.json())
.then((stats) => {
// Update header stats
document.querySelector(
".stat-item:nth-child(1) .stat-value",
).textContent = stats.total || 0;
document.querySelector(
".stat-item:nth-child(2) .stat-value",
).textContent = stats.active || 0;
document.querySelector(
".stat-item:nth-child(3) .stat-value",
).textContent = stats.completed || 0;
// Update tab counts
document.getElementById("count-all").textContent =
stats.total || 0;
document.getElementById("count-active").textContent =
stats.active || 0;
document.getElementById("count-completed").textContent =
stats.completed || 0;
document.getElementById("count-priority").textContent =
stats.priority || 0;
// Update footer text
const footerText = document.getElementById("footer-text");
if (stats.active === 0) {
footerText.innerHTML = "All tasks completed! 🎉";
} else {
footerText.innerHTML = `<strong>${stats.active}</strong> ${stats.active === 1 ? "task" : "tasks"} remaining`;
}
// Show/hide footer
const footer = document.getElementById("task-footer");
footer.style.display = stats.total > 0 ? "flex" : "none";
});
}
// Handle checkbox changes
document.addEventListener("change", function (e) {
if (e.target.classList.contains("task-checkbox")) {
const taskId = e.target.dataset.taskId;
const completed = e.target.checked;
fetch(`/api/tasks/${taskId}/status`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ completed }),
}).then(() => {
const taskItem = e.target.closest(".task-item");
if (completed) {
taskItem.classList.add("completed");
} else {
taskItem.classList.remove("completed");
}
updateStats();
});
}
});
// Handle task actions
document.addEventListener("click", function (e) {
// Priority toggle
if (e.target.closest('[data-action="priority"]')) {
const btn = e.target.closest('[data-action="priority"]');
const taskId = btn.dataset.taskId;
const priority = !btn.classList.contains("active");
fetch(`/api/tasks/${taskId}/priority`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ priority }),
}).then(() => {
btn.classList.toggle("active");
updateStats();
});
}
// Edit task
if (e.target.closest('[data-action="edit"]')) {
const btn = e.target.closest('[data-action="edit"]');
const taskId = btn.dataset.taskId;
const taskItem = btn.closest(".task-item");
const taskText = taskItem.querySelector(".task-text");
const currentText = taskText.textContent;
const input = document.createElement("input");
input.type = "text";
input.className = "task-edit-input";
input.value = currentText;
taskText.replaceWith(input);
input.focus();
input.select();
input.addEventListener("blur", function () {
saveEdit();
});
input.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
saveEdit();
} else if (e.key === "Escape") {
cancelEdit();
}
});
function saveEdit() {
const newText = input.value.trim();
if (newText && newText !== currentText) {
fetch(`/api/tasks/${taskId}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text: newText }),
}).then(() => {
const span = document.createElement("span");
span.className = "task-text";
span.textContent = newText;
input.replaceWith(span);
});
} else {
cancelEdit();
}
}
function cancelEdit() {
const span = document.createElement("span");
span.className = "task-text";
span.textContent = currentText;
input.replaceWith(span);
}
}
// Delete task
if (e.target.closest('[data-action="delete"]')) {
const btn = e.target.closest('[data-action="delete"]');
const taskId = btn.dataset.taskId;
if (confirm("Delete this task?")) {
fetch(`/api/tasks/${taskId}`, {
method: "DELETE",
}).then(() => {
const taskItem = btn.closest(".task-item");
taskItem.style.animation = "slideOut 0.3s ease";
setTimeout(() => {
taskItem.remove();
updateStats();
}, 300);
});
}
}
});
// Animation for removing tasks
const style = document.createElement("style");
style.textContent = `
@keyframes slideOut {
to {
opacity: 0;
transform: translateX(-100%);
}
}
`;
document.head.appendChild(style);
// Update stats after any HTMX request
document.body.addEventListener("htmx:afterSwap", function (evt) {
if (evt.detail.target.id === "task-list") {
updateStats();
}
});
// Initial stats load
document.addEventListener("DOMContentLoaded", function () {
updateStats();
});
// Keyboard shortcuts
document.addEventListener("keydown", function (e) {
// Alt + N for new task
if (e.altKey && e.key === "n") {
e.preventDefault();
document.querySelector(".task-input").focus();
}
// Alt + 1-4 for filter tabs
if (e.altKey && e.key >= "1" && e.key <= "4") {
e.preventDefault();
const tabs = document.querySelectorAll(".filter-tab");
const index = parseInt(e.key) - 1;
if (tabs[index]) {
tabs[index].click();
}
}
});