implemented a marked as complete button

This commit is contained in:
NPS Agent
2026-05-11 14:24:21 +09:30
parent 49dc767922
commit 4d7541caca
3 changed files with 29 additions and 5 deletions
+12 -1
View File
@@ -134,6 +134,17 @@ function App() {
} catch(e) {}
};
const completeTask = async (taskId) => {
try {
await api.updateTask(taskId, { status: 'closed' });
await api.addAudit({ actor: meId, action: 'task_completed', summary: 'Marked task as completed', target: taskId });
setOpenTaskId(null);
} catch(e) {
console.error(e);
alert("Failed to complete task: " + e.message);
}
};
const dismissHU = (id) => setHeadsUp(h => h.filter(x => x.id !== id));
const openTaskFromAnywhere = (id) => { setOpenTaskId(id); setShowLogs(false); };
@@ -191,7 +202,7 @@ function App() {
<AddTaskModal open={!!adding} onClose={() => setAdding(null)} onSubmit={addTask} defaultAssignee={adding} me={me} />
{mappedOpenTask && (
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} />
<TaskDetail task={mappedOpenTask} allAudit={frontendAudit} onClose={() => setOpenTaskId(null)} onMove={moveTask} onPriority={setPriority} onComplete={() => completeTask(mappedOpenTask.id)} />
)}
{showLogs && (
<Modal title="Audit log" onClose={() => setShowLogs(false)} wide>
BIN
View File
Binary file not shown.
+17 -4
View File
@@ -163,7 +163,7 @@ function HeadsUp({ items, onDismiss, onOpenTask }) {
function OverviewScreen({ tasks, onOpen, onAddFor, density, onMoveTask }) {
const byUser = Object.fromEntries(USERS.map(u => [u.id, []]));
tasks.forEach(t => { if (byUser[t.assignee]) byUser[t.assignee].push(t); });
tasks.forEach(t => { if (byUser[t.assignee] && t.status !== 'closed') byUser[t.assignee].push(t); });
const [draggingTask, setDraggingTask] = React.useState(null);
const [dragOverCol, setDragOverCol] = React.useState(null);
return (
@@ -244,13 +244,14 @@ function UserScreen({ user, tasks, onOpen, onAddFor, density }) {
const mine = tasks.filter(t => t.assignee === user.id);
const open = mine.filter(t => t.status === 'open');
const flagged = mine.filter(t => t.status === 'unsuccessful' || t.status === 'billing');
const closed = mine.filter(t => t.status === 'closed');
return (
<div className="user-view">
<div className="user-view__hero">
<Avatar user={user} size={64} />
<div className="user-view__hero-meta">
<h1 className="user-view__name">{user.name}</h1>
<p className="user-view__role">{user.role} · <span className="mono">{mine.length} tasks</span></p>
<p className="user-view__role">{user.role} · <span className="mono">{open.length + flagged.length} open tasks</span></p>
</div>
<div className="user-view__hero-cta">
<button className="btn btn--primary" onClick={() => onAddFor(user.id)}>
@@ -272,6 +273,14 @@ function UserScreen({ user, tasks, onOpen, onAddFor, density }) {
{open.map(t => <TaskCard key={t.id} task={t} onOpen={onOpen} density={density} />)}
</div>
</Section>
{closed.length > 0 && (
<Section title="Completed" sub={closed.length + ' tasks'}>
<div className="user-view__grid" style={{ opacity: 0.6 }}>
{closed.map(t => <TaskCard key={t.id} task={t} onOpen={onOpen} density={density} />)}
</div>
</Section>
)}
</div>
);
}
@@ -398,7 +407,7 @@ function Modal({ children, onClose, title, eyebrow, wide = false }) {
);
}
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority }) {
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete }) {
if (!task) return null;
const assignee = findUser(task.assignee);
const author = findUser(task.addedBy);
@@ -415,7 +424,7 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority }) {
<strong>Auto-marked Unsuccessful.</strong> Two missed bookings detected by the scheduler. Decide on next step or revert.
<div className="detail__alert-actions">
<button className="btn btn--ghost btn--sm">Revert to Open</button>
<button className="btn btn--soft btn--sm">Close as unsuccessful</button>
<button className="btn btn--soft btn--sm" onClick={onComplete}>Close as unsuccessful</button>
</div>
</div>
)}
@@ -478,6 +487,10 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority }) {
</div>
<aside className="detail__side">
<button className="btn btn--primary btn--full" style={{ marginBottom: '1.5rem' }} onClick={onComplete}>
<Icon.Check /> Mark as completed
</button>
<Field label="Assigned to">
<div className="picker">
{USERS.map(u => (