Made the ability to edit tasks and removed the placeholder notes and reminders from each task

This commit is contained in:
NPS Agent
2026-05-11 15:38:30 +09:30
parent 39d26be447
commit 13e92e2b27
4 changed files with 57 additions and 30 deletions
+10 -11
View File
@@ -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.
+11 -1
View File
@@ -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>
BIN
View File
Binary file not shown.
+36 -18
View File
@@ -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 &amp; reminders</h3> <h3 className="detail__h">Notes &amp; 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…" />