From 5b9f174718f25fb34daeeef05c1cb4b2ec424b94 Mon Sep 17 00:00:00 2001 From: rgrgogu Date: Thu, 16 Jul 2026 19:04:02 +0800 Subject: [PATCH] task list working --- src/contexts/AdminTaskContext.jsx | 4 +- .../task_list/task/archive/columns.config.jsx | 22 ++++++-- .../config/task_list/task/columns.config.jsx | 22 ++++++-- .../task_list/task/rowActions.config.jsx | 2 +- .../admin/pages/task_list/task/EditTask.jsx | 55 +++++++++---------- .../admin/pages/task_list/task/ViewTask.jsx | 30 +++++++++- .../admin/pages/task_list/task/task.schema.js | 2 +- 7 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/contexts/AdminTaskContext.jsx b/src/contexts/AdminTaskContext.jsx index 39d3ff7..7f2ea59 100644 --- a/src/contexts/AdminTaskContext.jsx +++ b/src/contexts/AdminTaskContext.jsx @@ -332,7 +332,7 @@ export function AdminTaskProvider({ children }) { request(async () => { const res = await api.post(`${BASE}/${taskListId}/tasks`, payload); toast('Task created.'); - return res.data?.data?.data ?? null; + return res.data?.data ?? null; }), [request] ); @@ -342,7 +342,7 @@ export function AdminTaskProvider({ children }) { request(async () => { const res = await api.patch(`${BASE}/${taskListId}/tasks/${taskId}`, payload); toast('Task updated.'); - return res.data?.data?.data ?? null; + return res.data?.data ?? null; }), [request] ); diff --git a/src/modules/admin/config/task_list/task/archive/columns.config.jsx b/src/modules/admin/config/task_list/task/archive/columns.config.jsx index 889c7c0..d5901f6 100644 --- a/src/modules/admin/config/task_list/task/archive/columns.config.jsx +++ b/src/modules/admin/config/task_list/task/archive/columns.config.jsx @@ -1,6 +1,7 @@ // config/columns.config.jsx -// Column definitions and pinning config for the Users table. +// Column definitions and pinning config for the Archived Tasks table. +import { format } from "date-fns"; import { buildColumns } from "@/utils/table.util"; import { buildSelectionColumn } from "@/components/generic/Table/buildSelectionColumn"; import { buildRowActionsColumn } from "@/components/generic/Table/buildRowActionsColumn"; @@ -10,8 +11,21 @@ export const columnPinning = { left: [], }; +// ─── Custom cell overrides ──────────────────────────────────────────────────── +const cellOverrides = { + deadline: (info) => { + const value = info.getValue(); + if (!value) return -; + return ( + + {format(new Date(value), "MMMM d, yyyy: h:mma")} + + ); + }, +}; + /** - * Builds the full column array for the Users table. + * Builds the full column array for the Archived Tasks table. * * @param {Array} attributes Field definitions from the server (drives data columns) * @param {Array} rowActions Row-level kebab action definitions @@ -22,7 +36,7 @@ export function buildDataColumns(attributes, rowActions) { return [ buildSelectionColumn(), - ...buildColumns(visibleAttributes), - buildRowActionsColumn(rowActions, { dropdownLabel: "User Actions" }), + ...buildColumns(visibleAttributes, { cellOverrides }), + buildRowActionsColumn(rowActions, { dropdownLabel: "Task Actions" }), ]; } \ No newline at end of file diff --git a/src/modules/admin/config/task_list/task/columns.config.jsx b/src/modules/admin/config/task_list/task/columns.config.jsx index 889c7c0..4e5c8bb 100644 --- a/src/modules/admin/config/task_list/task/columns.config.jsx +++ b/src/modules/admin/config/task_list/task/columns.config.jsx @@ -1,6 +1,7 @@ // config/columns.config.jsx -// Column definitions and pinning config for the Users table. +// Column definitions and pinning config for the Tasks table. +import { format } from "date-fns"; import { buildColumns } from "@/utils/table.util"; import { buildSelectionColumn } from "@/components/generic/Table/buildSelectionColumn"; import { buildRowActionsColumn } from "@/components/generic/Table/buildRowActionsColumn"; @@ -10,8 +11,21 @@ export const columnPinning = { left: [], }; +// ─── Custom cell overrides ──────────────────────────────────────────────────── +const cellOverrides = { + deadline: (info) => { + const value = info.getValue(); + if (!value) return -; + return ( + + {format(new Date(value), "MMMM d, yyyy: h:mma")} + + ); + }, +}; + /** - * Builds the full column array for the Users table. + * Builds the full column array for the Tasks table. * * @param {Array} attributes Field definitions from the server (drives data columns) * @param {Array} rowActions Row-level kebab action definitions @@ -22,7 +36,7 @@ export function buildDataColumns(attributes, rowActions) { return [ buildSelectionColumn(), - ...buildColumns(visibleAttributes), - buildRowActionsColumn(rowActions, { dropdownLabel: "User Actions" }), + ...buildColumns(visibleAttributes, { cellOverrides }), + buildRowActionsColumn(rowActions, { dropdownLabel: "Task Actions" }), ]; } \ No newline at end of file diff --git a/src/modules/admin/config/task_list/task/rowActions.config.jsx b/src/modules/admin/config/task_list/task/rowActions.config.jsx index 7578eb4..45c7da1 100644 --- a/src/modules/admin/config/task_list/task/rowActions.config.jsx +++ b/src/modules/admin/config/task_list/task/rowActions.config.jsx @@ -22,6 +22,7 @@ export function buildRowActions({ navigate, onArchive, onRestore, onMoveUp, onMo icon: , onClick: (row) => onMoveUp(row), hidden: () => showArchived, + separator: true, disabled: (row) => tasks.findIndex((t) => t.task_id === row.task_id) <= 0, }, { @@ -30,7 +31,6 @@ export function buildRowActions({ navigate, onArchive, onRestore, onMoveUp, onMo icon: , onClick: (row) => onMoveDown(row), hidden: () => showArchived, - separator: true, disabled: (row) => tasks.findIndex((t) => t.task_id === row.task_id) >= tasks.length - 1, }, { diff --git a/src/modules/admin/pages/task_list/task/EditTask.jsx b/src/modules/admin/pages/task_list/task/EditTask.jsx index 207cc97..71d2caa 100644 --- a/src/modules/admin/pages/task_list/task/EditTask.jsx +++ b/src/modules/admin/pages/task_list/task/EditTask.jsx @@ -14,6 +14,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Switch } from '@/components/ui/switch'; import { Skeleton } from '@/components/ui/skeleton'; +import DeadlinePicker from '@/components/generic/DeadlinePicker'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, @@ -51,9 +52,7 @@ export default function EditTask() { setForm({ name: data.name ?? '', description: data.description ?? '', - deadline: data.deadline - ? new Date(data.deadline).toISOString().slice(0, 16) - : '', + deadline: data.deadline ?? '', status: data.status ?? 'pending', is_required: data.is_required ?? true, requirements: reqs, @@ -185,32 +184,30 @@ export default function EditTask() { /> -
-
- - setForm({ ...form, deadline: e.target.value })} - /> -
-
- - -
+
+ + setForm({ ...form, deadline: iso })} + disabled={loading} + /> +
+ +
+ +
diff --git a/src/modules/admin/pages/task_list/task/ViewTask.jsx b/src/modules/admin/pages/task_list/task/ViewTask.jsx index 45e5fa8..97cf914 100644 --- a/src/modules/admin/pages/task_list/task/ViewTask.jsx +++ b/src/modules/admin/pages/task_list/task/ViewTask.jsx @@ -12,6 +12,7 @@ import { ArrowLeft, Pencil, FileText, CalendarClock, Link2, Upload, BookOpen, BookMarked, FileCheck2, Info, GitPullRequest, Tag, Globe, Copy, File, Bookmark, + ClipboardCheck, } from 'lucide-react'; // ─── Same config as ViewTaskList — label, icon only, all styling via shadcn tokens @@ -128,8 +129,8 @@ function TaskRequirementsSection({ requirements = [] }) { export default function ViewTask() { const navigate = useNavigate(); const { taskListId, taskId } = useParams(); - const { fetchTask } = useAdminTask(); - const { fmtDate } = useDateFormat(); + const { fetchTask, fetchCompletions, completionPagination, completionLoading } = useAdminTask(); + const { fmtDateTime } = useDateFormat(); const [task, setTask] = useState(null); @@ -138,6 +139,7 @@ export default function ViewTask() { if (!data) return; setTask(data); }); + fetchCompletions(taskListId, taskId, { page: 1, limit: 1 }); }, [taskListId, taskId]); if (!task) return ( @@ -202,7 +204,7 @@ export default function ViewTask() { Deadline:{' '} - {fmtDate(task.deadline)} + {fmtDateTime(task.deadline)}
@@ -224,6 +226,28 @@ export default function ViewTask() { )} + {/* Completions */} + +
+
+ Completions +
+
+ + {completionLoading + ? '…' + : `${completionPagination.totalRecords} submission${completionPagination.totalRecords === 1 ? '' : 's'}`} + + +
+
+ {/* Requirements */} diff --git a/src/modules/admin/pages/task_list/task/task.schema.js b/src/modules/admin/pages/task_list/task/task.schema.js index e9bfe9e..31ca2b9 100644 --- a/src/modules/admin/pages/task_list/task/task.schema.js +++ b/src/modules/admin/pages/task_list/task/task.schema.js @@ -16,7 +16,7 @@ function normalizeLinkUrl(url) { export const requirementSchema = z.object({ type: z.string(), - reference_id: z.string().optional(), + reference_id: z.string().nullable().optional(), duration_seconds: z.number().optional(), }).passthrough().superRefine((req, ctx) => { if (!READ_TYPES.includes(req.type)) return;