From 56da866a75a69592843c74233379a51cae531717 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 1 Apr 2026 18:38:41 +0000
Subject: [PATCH] feat: add category selection (Low/Medium/High) to tasks
Agent-Logs-Url: https://github.com/CleveritDemo/copilot-agentic-workshop/sessions/b5fe920d-8b52-457b-a8bc-51fd09f1fdee
Co-authored-by: saulCleverit <121240069+saulCleverit@users.noreply.github.com>
---
backend/controllers/tasksController.js | 15 ++++++-
frontend/index.html | 5 +++
frontend/script.js | 34 +++++++++++----
frontend/style.css | 58 ++++++++++++++++++++++++++
4 files changed, 101 insertions(+), 11 deletions(-)
diff --git a/backend/controllers/tasksController.js b/backend/controllers/tasksController.js
index 745738d..6a1487e 100644
--- a/backend/controllers/tasksController.js
+++ b/backend/controllers/tasksController.js
@@ -12,14 +12,19 @@ function writeTasks(tasks) {
fs.writeFileSync(filePath, JSON.stringify(tasks, null, 2));
}
+const VALID_CATEGORIES = ['Low', 'Medium', 'High'];
+
exports.getAllTasks = (req, res) => {
res.json(readTasks());
};
exports.createTask = (req, res) => {
const tasks = readTasks();
- const { title, completed = false } = req.body;
- const newTask = { id: uuidv4(), title, completed };
+ const { title, completed = false, category = 'Medium' } = req.body;
+ if (!VALID_CATEGORIES.includes(category)) {
+ return res.status(400).json({ message: `Invalid category. Must be one of: ${VALID_CATEGORIES.join(', ')}` });
+ }
+ const newTask = { id: uuidv4(), title, completed, category };
tasks.push(newTask);
writeTasks(tasks);
res.status(201).json(newTask);
@@ -32,6 +37,12 @@ exports.updateTask = (req, res) => {
task.title = req.body.title ?? task.title;
task.completed = req.body.completed ?? task.completed;
+ if (req.body.category !== undefined) {
+ if (!VALID_CATEGORIES.includes(req.body.category)) {
+ return res.status(400).json({ message: `Invalid category. Must be one of: ${VALID_CATEGORIES.join(', ')}` });
+ }
+ task.category = req.body.category;
+ }
writeTasks(tasks);
res.json(task);
};
diff --git a/frontend/index.html b/frontend/index.html
index 915426f..c3e128b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -14,6 +14,11 @@
Task List
diff --git a/frontend/script.js b/frontend/script.js
index a519ccf..6ad5c00 100644
--- a/frontend/script.js
+++ b/frontend/script.js
@@ -1,9 +1,11 @@
const API_URL = 'http://localhost:3000/api/tasks';
+const CATEGORIES = ['Low', 'Medium', 'High'];
+const DEFAULT_CATEGORY = 'Medium';
const taskList = document.getElementById('taskList');
const taskForm = document.getElementById('taskForm');
const taskInput = document.getElementById('taskInput');
+const categorySelect = document.getElementById('categorySelect');
const themeToggle = document.getElementById('themeToggle');
-
// Theme functionality
function initTheme() {
const savedTheme = localStorage.getItem('theme') || 'light';
@@ -35,28 +37,42 @@ async function fetchTasks() {
}
function addTaskToDOM(task) {
+ const category = task.category || DEFAULT_CATEGORY;
const li = document.createElement('li');
- li.innerHTML = `
- ${task.title}
-
-
-
-
- `;
+ const titleSpan = document.createElement('span');
+ titleSpan.className = task.completed ? 'completed' : '';
+ titleSpan.textContent = task.title;
+ const categoryBadge = document.createElement('span');
+ categoryBadge.className = `category-badge category-${category.toLowerCase()}`;
+ categoryBadge.textContent = category;
+ const actions = document.createElement('div');
+ const completeBtn = document.createElement('button');
+ completeBtn.textContent = '✓';
+ completeBtn.onclick = () => toggleComplete(task.id, !task.completed);
+ const deleteBtn = document.createElement('button');
+ deleteBtn.textContent = '✕';
+ deleteBtn.onclick = () => deleteTask(task.id);
+ actions.appendChild(completeBtn);
+ actions.appendChild(deleteBtn);
+ li.appendChild(titleSpan);
+ li.appendChild(categoryBadge);
+ li.appendChild(actions);
taskList.appendChild(li);
}
taskForm.addEventListener('submit', async e => {
e.preventDefault();
const title = taskInput.value;
+ const category = categorySelect.value;
const res = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ title })
+ body: JSON.stringify({ title, category })
});
const task = await res.json();
addTaskToDOM(task);
taskInput.value = '';
+ categorySelect.value = DEFAULT_CATEGORY;
});
async function toggleComplete(id, completed) {
diff --git a/frontend/style.css b/frontend/style.css
index d351594..7dc4c6a 100644
--- a/frontend/style.css
+++ b/frontend/style.css
@@ -189,3 +189,61 @@ li button:active {
padding: 0.75em 0.5em;
}
}
+
+#categorySelect {
+ padding: 0.75em 0.5em;
+ border: none;
+ border-radius: 4px;
+ background: var(--input-bg);
+ color: var(--text-color);
+ box-shadow: 0 1px 2px var(--input-shadow);
+ font-size: 1em;
+ cursor: pointer;
+ outline: none;
+ transition: box-shadow 0.2s;
+}
+
+#categorySelect:focus {
+ box-shadow: 0 2px 8px var(--input-focus-shadow);
+}
+
+.category-badge {
+ font-size: 0.75em;
+ font-weight: 500;
+ padding: 0.2em 0.65em;
+ border-radius: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ margin: 0 0.5em;
+ flex-shrink: 0;
+}
+
+.category-low {
+ background-color: #e8f5e9;
+ color: #2e7d32;
+}
+
+.category-medium {
+ background-color: #fff3e0;
+ color: #e65100;
+}
+
+.category-high {
+ background-color: #fce4ec;
+ color: #c62828;
+}
+
+[data-theme="dark"] .category-low {
+ background-color: #1b5e20;
+ color: #a5d6a7;
+}
+
+[data-theme="dark"] .category-medium {
+ background-color: #bf360c;
+ color: #ffcc80;
+}
+
+[data-theme="dark"] .category-high {
+ background-color: #880e4f;
+ color: #f48fb1;
+}