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; +}