Made the ability to edit tasks and removed the placeholder notes and reminders from each task
This commit is contained in:
+10
-11
@@ -42,17 +42,16 @@
|
|||||||
## ⏭️ Upcoming Steps
|
## ⏭️ Upcoming Steps
|
||||||
|
|
||||||
### Phase 2: Frontend Refactor & Workflow Polish (✅ Completed)
|
### Phase 2: Frontend Refactor & Workflow Polish (✅ Completed)
|
||||||
1. **API Service:** Created `api.js` to dynamically connect to the backend (resolved connection refused issues by using dynamic hostnames) and handle all network requests.
|
1. **API Integration:** Created `api.js` to handle network requests, swapped `DashyDB` for async API calls in `app.jsx`, and updated Login to use JWT tokens.
|
||||||
2. **Authentication Hook:** Updated the Login screen to use real JWT tokens.
|
2. **Legacy Cleanup:** Archived `db.js` and `data.jsx` to `Dashy-v1/scraps/` and removed `sql.js` WASM dependency from `Dashy.html`.
|
||||||
3. **Component Updates:**
|
3. **API Base URL Fix:** Updated `api.js` to dynamically use the browser's hostname to resolve "Connection Refused" errors.
|
||||||
- Swapped `DashyDB` calls for `async` API calls in `app.jsx`.
|
4. **Audit Rendering Crash Fix:** Resolved the `TASK_AUDIT` ReferenceError by passing live API audit logs into the `TaskDetail` modal.
|
||||||
- Fixed UI state refresh issues by silently loading subsequent data updates.
|
5. **UI State Refresh Fix:** Modified the `useApiData` hook to fetch subsequent updates silently without unmounting the app (fixing the drag-and-drop refresh bug).
|
||||||
4. **Task Workflows:**
|
6. **Task Completion:** Added a "Mark as completed" button, removed closed tasks from the main Overview board, and set up audit logging.
|
||||||
- **Completion:** Added a "Mark as completed" button in `TaskDetail` that changes task status to `closed`, records it in the Audit Log, and removes the task from the main Overview board.
|
7. **User Views Update:** Updated `UserScreen` to accurately display open task counts and render a dedicated, faded "Completed" section for closed tasks.
|
||||||
- **Reopening:** Added a "Reopen task" button to restore accidentally closed tasks back to the queue.
|
8. **Task Reopening:** Added a "Reopen task" button to restore accidentally closed tasks back to the queue.
|
||||||
- **User Views:** Updated `UserScreen` to accurately display open task counts and render a dedicated, faded "Completed" section at the bottom for closed tasks.
|
9. **User Management (Settings):** Built backend API endpoints (`POST`, `PATCH`, `DELETE` for `/users`) and wired up the `WorkspaceTab` allowing Admins to manage the team from the UI.
|
||||||
- **Audit Rendering:** Fixed crash in `TaskDetail` by passing global API audit logs and filtering them locally for individual tasks.
|
10. **Task Editing:** Implemented inline editing for task descriptions using an active text box state with "Save/Cancel" actions.
|
||||||
5. **Cleanup:** Archived `db.js`, `data.jsx` to `Dashy-v1/scraps/` and removed `sql.js` WASM dependency from `Dashy.html`.
|
|
||||||
|
|
||||||
### Phase 3: Advanced Features
|
### Phase 3: Advanced Features
|
||||||
- **Real-time Notifications:** Explore WebSockets for task assignments.
|
- **Real-time Notifications:** Explore WebSockets for task assignments.
|
||||||
|
|||||||
@@ -156,6 +156,16 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editTaskDesc = async (taskId, newDesc) => {
|
||||||
|
try {
|
||||||
|
await api.updateTask(taskId, { description: newDesc });
|
||||||
|
await api.addAudit({ actor: meId, action: 'task_edited', summary: 'Updated task description', target: taskId });
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
|
alert("Failed to update description: " + e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id));
|
const dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id));
|
||||||
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
|
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
|
||||||
|
|
||||||
@@ -213,7 +223,7 @@ function App() {
|
|||||||
|
|
||||||
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} />
|
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} />
|
||||||
{mappedOpenTask && (
|
{mappedOpenTask && (
|
||||||
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} />
|
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} onReopen={() => reopenTask(mappedOpenTask.id)} onEditDesc={(newDesc) => editTaskDesc(mappedOpenTask.id, newDesc)} />
|
||||||
)}
|
)}
|
||||||
{showLogs && (
|
{showLogs && (
|
||||||
<Modal title="Audit log" onClose={() => setShowLogs(false)} wide>
|
<Modal title="Audit log" onClose={() => setShowLogs(false)} wide>
|
||||||
|
|||||||
+35
-17
@@ -407,7 +407,14 @@ function Modal({ children, onClose, title, eyebrow, wide = false }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen }) {
|
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen, onEditDesc }) {
|
||||||
|
const [editingDesc, setEditingDesc] = React.useState(false);
|
||||||
|
const [descValue, setDescValue] = React.useState(task ? task.description || '' : '');
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setDescValue(task ? task.description || '' : '');
|
||||||
|
}, [task]);
|
||||||
|
|
||||||
if (!task) return null;
|
if (!task) return null;
|
||||||
const assignee = findUser(task.assignee);
|
const assignee = findUser(task.assignee);
|
||||||
const author = findUser(task.addedBy);
|
const author = findUser(task.addedBy);
|
||||||
@@ -434,27 +441,38 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{task.description && (
|
<div className="detail__desc-section" style={{ marginBottom: '1.5rem' }}>
|
||||||
<p className="detail__desc">{task.description}</p>
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '0.5rem' }}>
|
||||||
|
<h3 className="detail__h" style={{ margin: 0 }}>Description</h3>
|
||||||
|
{!editingDesc && (
|
||||||
|
<IconBtn label="Edit description" onClick={() => setEditingDesc(true)}>
|
||||||
|
<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M12.5 3.5l-8 8V14h2.5l8-8-2.5-2.5z" strokeLinecap="round" strokeLinejoin="round"/><path d="M10.5 5.5l2 2" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
||||||
|
</IconBtn>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
{editingDesc ? (
|
||||||
|
<div className="detail__desc-edit">
|
||||||
|
<textarea
|
||||||
|
className="field__textarea"
|
||||||
|
value={descValue}
|
||||||
|
onChange={e => setDescValue(e.target.value)}
|
||||||
|
autoFocus
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
|
<div className="detail__alert-actions" style={{ marginTop: '0.5rem' }}>
|
||||||
|
<button className="btn btn--ghost btn--sm" onClick={() => { setDescValue(task.description || ''); setEditingDesc(false); }}>Cancel</button>
|
||||||
|
<button className="btn btn--primary btn--sm" onClick={() => { onEditDesc(descValue); setEditingDesc(false); }}>Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="detail__desc" style={{ marginTop: 0 }}>{task.description || <span className="mono" style={{opacity: 0.5}}>No description</span>}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="detail__notes">
|
<div className="detail__notes">
|
||||||
<h3 className="detail__h">Notes & reminders</h3>
|
<h3 className="detail__h">Notes & reminders</h3>
|
||||||
<ul className="notes">
|
<ul className="notes">
|
||||||
<li className="notes__item">
|
{/* Dynamic notes will go here */}
|
||||||
<span className="notes__bullet"><Icon.Pin /></span>
|
|
||||||
<div>
|
|
||||||
<div>Customer wants pickup before <strong>Friday 3pm</strong>.</div>
|
|
||||||
<div className="notes__meta mono">Lani · 09:14</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="notes__item">
|
|
||||||
<span className="notes__bullet"><Icon.Bell /></span>
|
|
||||||
<div>
|
|
||||||
<div>Reminder set for <strong>Thu 4pm</strong> if no response by then.</div>
|
|
||||||
<div className="notes__meta mono">auto · 2h before due</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<div className="notes__add">
|
<div className="notes__add">
|
||||||
<input className="field__input" placeholder="Add a note or @mention…" />
|
<input className="field__input" placeholder="Add a note or @mention…" />
|
||||||
|
|||||||
Reference in New Issue
Block a user