diff --git a/README.md b/README.md index a6affaa..a99589f 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,13 @@ A simple task management application with a Java Spring Boot backend and React f ## Features - Create, read, update, and delete tasks +- **Enhanced Edit Task Functionality** with visual indicators and user feedback - Mark tasks as completed - Filter tasks by status (all, active, completed) - Set task priority (low, medium, high) - Set due dates for tasks +- Real-time visual feedback for edit operations +- Intuitive edit mode with distinct styling and notifications ## Tech Stack @@ -101,3 +104,35 @@ task-manager/ - `PUT /api/tasks/{id}` - Update a task - `PATCH /api/tasks/{id}/toggle` - Toggle task completion status - `DELETE /api/tasks/{id}` - Delete a task + +## Edit Task Feature + +The application includes a comprehensive edit task functionality with the following enhancements: + +### How to Edit a Task + +1. **Click the Edit Button**: Each task has an orange "Edit" button (✏️ Edit) in the task actions area +2. **Visual Feedback**: When editing: + - The task form switches to "Edit Mode" with orange styling and an edit icon + - The task being edited is highlighted with an orange border and "Currently editing" indicator + - A notification shows which task you're editing +3. **Make Changes**: Modify any task fields (title, description, priority, due date) +4. **Save or Cancel**: + - Click "💾 Update Task" to save changes + - Click "❌ Cancel" to exit edit mode without saving +5. **Success Confirmation**: A green success message confirms when the task is updated + +### Edit Mode Visual Indicators + +- **Form Styling**: Orange background and border when in edit mode +- **Task Highlighting**: The task being edited has a distinct orange highlight +- **Button States**: Edit buttons are disabled for the task currently being edited +- **Icons and Emojis**: Visual cues throughout the interface (✏️, 💾, ❌, ✅) +- **Success Messages**: Clear feedback when operations complete successfully + +### Technical Implementation + +- **Backend**: RESTful PUT endpoint at `/api/tasks/{id}` handles task updates +- **Frontend**: React state management with visual feedback and form validation +- **Real-time Updates**: Immediate UI updates without page refresh +- **Error Handling**: Comprehensive error messages and recovery options diff --git a/frontend/src/App.js b/frontend/src/App.js index 7940efa..1f076c5 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -10,6 +10,7 @@ function App() { const [error, setError] = useState(null); const [filter, setFilter] = useState('all'); const [editingTask, setEditingTask] = useState(null); + const [successMessage, setSuccessMessage] = useState(null); useEffect(() => { fetchTasks(); @@ -33,6 +34,8 @@ function App() { try { const newTask = await createTask(taskData); setTasks([newTask, ...tasks]); + setSuccessMessage('Task created successfully!'); + setTimeout(() => setSuccessMessage(null), 3000); } catch (err) { setError('Failed to create task. Please try again.'); console.error('Error creating task:', err); @@ -44,6 +47,8 @@ function App() { const updatedTask = await updateTask(id, taskData); setTasks(tasks.map(task => task.id === id ? updatedTask : task)); setEditingTask(null); + setSuccessMessage(`Task "${updatedTask.title}" updated successfully!`); + setTimeout(() => setSuccessMessage(null), 3000); } catch (err) { setError('Failed to update task. Please try again.'); console.error('Error updating task:', err); @@ -72,6 +77,8 @@ function App() { const handleEditTask = (task) => { setEditingTask(task); + setSuccessMessage(null); // Clear any existing success messages + setError(null); // Clear any existing error messages }; const filteredTasks = tasks.filter(task => { @@ -88,6 +95,7 @@ function App() { {error &&
{error}
} + {successMessage &&
{successMessage}
} handleUpdateTask(editingTask.id, taskData) : handleCreateTask} @@ -105,6 +113,7 @@ function App() { onDelete={handleDeleteTask} onToggleCompletion={handleToggleCompletion} onEdit={handleEditTask} + editingTaskId={editingTask?.id} /> )} diff --git a/frontend/src/components/TaskForm.js b/frontend/src/components/TaskForm.js index a147d57..3292b40 100644 --- a/frontend/src/components/TaskForm.js +++ b/frontend/src/components/TaskForm.js @@ -37,8 +37,21 @@ const TaskForm = ({ onSubmit, initialData, onCancel }) => { }; return ( -
+

{initialData ? 'Edit Task' : 'Add New Task'}

+ {initialData && ( +
+ 📝 You are currently editing: "{initialData.title}" +
+ )}
@@ -84,14 +97,14 @@ const TaskForm = ({ onSubmit, initialData, onCancel }) => {
- {onCancel && ( diff --git a/frontend/src/components/TaskList.js b/frontend/src/components/TaskList.js index c948157..3cfea5f 100644 --- a/frontend/src/components/TaskList.js +++ b/frontend/src/components/TaskList.js @@ -1,7 +1,7 @@ import React from 'react'; import TaskItem from './TaskItem'; -const TaskList = ({ tasks, onDelete, onToggleCompletion, onEdit }) => { +const TaskList = ({ tasks, onDelete, onToggleCompletion, onEdit, editingTaskId }) => { if (tasks.length === 0) { return

No tasks found. Add a new task to get started!

; } @@ -15,6 +15,7 @@ const TaskList = ({ tasks, onDelete, onToggleCompletion, onEdit }) => { onDelete={onDelete} onToggleCompletion={onToggleCompletion} onEdit={onEdit} + isEditing={editingTaskId === task.id} /> ))} diff --git a/frontend/src/index.css b/frontend/src/index.css index 3e637ba..8397990 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -30,6 +30,25 @@ code { border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); margin-bottom: 20px; + transition: all 0.3s ease; +} + +.task-form.edit-mode { + background-color: #fff3e0; + border: 2px solid #ff9800; + box-shadow: 0 4px 8px rgba(255, 152, 0, 0.2); +} + +.task-form.edit-mode h2 { + color: #e65100; + display: flex; + align-items: center; + gap: 8px; +} + +.task-form.edit-mode h2::before { + content: "✏️"; + font-size: 1.2em; } .form-group { @@ -64,6 +83,59 @@ code { cursor: pointer; font-size: 16px; font-weight: 600; + transition: all 0.2s ease; +} + +.btn-edit { + background-color: #ff9800; + color: white; + display: flex; + align-items: center; + gap: 5px; +} + +.btn-edit:hover { + background-color: #f57c00; + transform: translateY(-1px); +} + +.btn-edit::before { + content: "✏️"; + font-size: 0.9em; +} + +.btn-update { + background-color: #ff9800; + color: white; + display: flex; + align-items: center; + gap: 5px; +} + +.btn-update:hover { + background-color: #f57c00; +} + +.btn-update::before { + content: "💾"; + font-size: 0.9em; +} + +.btn-cancel { + background-color: #757575; + color: white; + display: flex; + align-items: center; + gap: 5px; +} + +.btn-cancel:hover { + background-color: #616161; +} + +.btn-cancel::before { + content: "❌"; + font-size: 0.8em; } .btn-primary { @@ -89,6 +161,26 @@ code { padding: 0; } +.task-item.editing { + background-color: #fff3e0; + border: 2px solid #ff9800; + box-shadow: 0 4px 8px rgba(255, 152, 0, 0.2); + transform: scale(1.02); +} + +.task-item.editing::before { + content: "Currently editing this task"; + position: absolute; + top: -10px; + left: 10px; + background-color: #ff9800; + color: white; + padding: 2px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 600; +} + .task-item { background-color: white; padding: 15px; @@ -98,6 +190,8 @@ code { display: flex; justify-content: space-between; align-items: center; + position: relative; + transition: all 0.3s ease; } .task-item.completed { @@ -161,3 +255,29 @@ code { .priority-low { border-left: 4px solid #4caf50; } + +.error-message { + background-color: #ffebee; + color: #c62828; + padding: 12px; + border-radius: 4px; + margin-bottom: 20px; + border-left: 4px solid #f44336; +} + +.success-message { + background-color: #e8f5e8; + color: #2e7d32; + padding: 12px; + border-radius: 4px; + margin-bottom: 20px; + border-left: 4px solid #4caf50; + display: flex; + align-items: center; + gap: 8px; +} + +.success-message::before { + content: "✅"; + font-size: 1.1em; +}