diff --git a/frontend/script.js b/frontend/script.js
index a519ccf..450e80f 100644
--- a/frontend/script.js
+++ b/frontend/script.js
@@ -37,8 +37,9 @@ async function fetchTasks() {
function addTaskToDOM(task) {
const li = document.createElement('li');
li.innerHTML = `
- ${task.title}
+ ${task.title}
+
@@ -73,4 +74,90 @@ async function deleteTask(id) {
fetchTasks();
}
+function editTask(id) {
+ const span = document.querySelector(`span[data-task-id="${id}"]`);
+ if (!span) return;
+
+ const currentTitle = span.textContent;
+ const wasCompleted = span.classList.contains('completed');
+
+ // Create input field
+ const input = document.createElement('input');
+ input.type = 'text';
+ input.value = currentTitle;
+ input.className = 'edit-input';
+ input.setAttribute('data-task-id', id);
+
+ // Create save button
+ const saveBtn = document.createElement('button');
+ saveBtn.textContent = '✓';
+ saveBtn.className = 'save-btn';
+ saveBtn.title = 'Save changes';
+ saveBtn.onclick = () => saveEdit(id);
+
+ // Create cancel button
+ const cancelBtn = document.createElement('button');
+ cancelBtn.textContent = '✕';
+ cancelBtn.className = 'cancel-btn';
+ cancelBtn.title = 'Cancel editing';
+ cancelBtn.onclick = () => cancelEdit(id, currentTitle, wasCompleted);
+
+ // Replace span with input
+ span.replaceWith(input);
+
+ // Replace action buttons with save/cancel buttons
+ const buttonDiv = input.parentElement.querySelector('div');
+ buttonDiv.innerHTML = '';
+ buttonDiv.appendChild(saveBtn);
+ buttonDiv.appendChild(cancelBtn);
+
+ // Focus input and select text
+ input.focus();
+ input.select();
+
+ // Allow Enter key to save
+ input.addEventListener('keypress', (e) => {
+ if (e.key === 'Enter') {
+ saveEdit(id);
+ }
+ });
+
+ // Allow Escape key to cancel
+ input.addEventListener('keydown', (e) => {
+ if (e.key === 'Escape') {
+ cancelEdit(id, currentTitle, wasCompleted);
+ }
+ });
+}
+
+async function saveEdit(id) {
+ const input = document.querySelector(`input[data-task-id="${id}"]`);
+ if (!input) return;
+
+ const newTitle = input.value.trim();
+
+ // Validate that title is not empty
+ if (!newTitle) {
+ alert('El título de la tarea no puede estar vacío');
+ input.focus();
+ return;
+ }
+
+ try {
+ await fetch(`${API_URL}/${id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ title: newTitle })
+ });
+ fetchTasks();
+ } catch (error) {
+ alert('Error al actualizar la tarea');
+ console.error(error);
+ }
+}
+
+function cancelEdit(id, originalTitle, wasCompleted) {
+ fetchTasks();
+}
+
fetchTasks();
diff --git a/frontend/style.css b/frontend/style.css
index d351594..be746d9 100644
--- a/frontend/style.css
+++ b/frontend/style.css
@@ -173,6 +173,42 @@ li button:hover {
li button:active {
background: var(--button-active-bg);
}
+.edit-input {
+ flex: 1;
+ padding: 0.5em 0.75em;
+ border: 2px solid var(--primary-color);
+ border-radius: 4px;
+ background: var(--input-bg);
+ color: var(--text-color);
+ font-size: 1.05em;
+ outline: none;
+ transition: box-shadow 0.2s;
+}
+.edit-input:focus {
+ box-shadow: 0 0 0 3px var(--input-focus-shadow);
+}
+.save-btn {
+ background: #4caf50 !important;
+ color: white !important;
+ border-radius: 4px !important;
+ width: auto !important;
+ padding: 0 0.75em !important;
+ font-weight: 500;
+}
+.save-btn:hover {
+ background: #45a049 !important;
+}
+.cancel-btn {
+ background: #f44336 !important;
+ color: white !important;
+ border-radius: 4px !important;
+ width: auto !important;
+ padding: 0 0.75em !important;
+ font-weight: 500;
+}
+.cancel-btn:hover {
+ background: #da190b !important;
+}
@media (max-width: 600px) {
body {
max-width: 100vw;