From 45adaa2f7636772e79e954769caa084ae172bbbc Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Wed, 29 Apr 2026 23:46:49 +0200 Subject: [PATCH] feat(ST-1112): refactor task-list to open TaskDialog via URL params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces inline create/edit forms with router.push navigation: - Clicking a task row → ?editTask= - "+ Taak" button → ?newTask=1&storyId= Removes CreateTaskForm, EditSubmitButton, updateTaskAction, and createTaskAction from the component. Status toggle and DnD remain unchanged. Rows now have cursor-pointer and keyboard a11y. Co-Authored-By: Claude Sonnet 4.6 --- components/sprint/task-list.tsx | 187 ++++++++++++++------------------ 1 file changed, 79 insertions(+), 108 deletions(-) diff --git a/components/sprint/task-list.tsx b/components/sprint/task-list.tsx index 99650c3..028e449 100644 --- a/components/sprint/task-list.tsx +++ b/components/sprint/task-list.tsx @@ -1,7 +1,7 @@ 'use client' -import { useState, useTransition, useEffect, useActionState } from 'react' -import { useFormStatus } from 'react-dom' +import { useState, useTransition, useEffect } from 'react' +import { useRouter, usePathname } from 'next/navigation' import { DndContext, DragEndEvent, DragOverlay, KeyboardSensor, PointerSensor, useSensor, useSensors, closestCenter, @@ -13,17 +13,13 @@ import { import { CSS } from '@dnd-kit/utilities' import { toast } from 'sonner' import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { CodeBadge } from '@/components/shared/code-badge' import { PanelNavBar } from '@/components/shared/panel-nav-bar' import { PRIORITY_BORDER } from '@/components/backlog/backlog-card' import { deriveTaskCode } from '@/lib/code' import { useSprintStore } from '@/stores/sprint-store' -import { - createTaskAction, updateTaskStatusAction, updateTaskAction, - deleteTaskAction, reorderTasksAction, -} from '@/actions/tasks' +import { updateTaskStatusAction, reorderTasksAction } from '@/actions/tasks' import { DemoTooltip } from '@/components/shared/demo-tooltip' import { cn } from '@/lib/utils' @@ -60,69 +56,69 @@ interface TaskListProps { } function SortableTaskRow({ - task, code, isDemo, onStatusToggle, onDelete, -}: { task: Task; code: string | null; isDemo: boolean; onStatusToggle: () => void; onDelete: () => void }) { - const [editing, setEditing] = useState(false) + task, code, isDemo, onStatusToggle, onEdit, +}: { + task: Task + code: string | null + isDemo: boolean + onStatusToggle: () => void + onEdit: () => void +}) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: task.id }) const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.4 : 1 } - const [, formAction] = useActionState( - async (_prev: unknown, fd: FormData) => { - const result = await updateTaskAction(_prev, fd) - if (result?.success) setEditing(false) - return result - }, - undefined - ) - - if (editing) { - return ( -
-
-
- - - -
- - -
-
-
-
- ) - } - return (
-
+
onEdit()} + role="button" + tabIndex={0} + aria-label={`Bewerk taak: ${task.title}`} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + onEdit() + } + }} + > {!isDemo && ( - + e.stopPropagation()} + className="text-muted-foreground cursor-grab active:cursor-grabbing shrink-0 text-sm select-none mt-0.5" + aria-hidden="true" + > + ⠿ + )}
-

+

{task.title}

{code && }
-
- -
- - - - - - -
@@ -130,48 +126,12 @@ function SortableTaskRow({ ) } -function EditSubmitButton() { - const { pending } = useFormStatus() - return -} - -function CreateTaskForm({ storyId, sprintId, onDone }: { storyId: string; sprintId: string; onDone: () => void }) { - const [state, formAction] = useActionState( - async (_prev: unknown, fd: FormData) => { - const result = await createTaskAction(_prev, fd) - if (result?.success) { onDone(); return result } - if (result?.error) toast.error(typeof result.error === 'string' ? result.error : 'Aanmaken mislukt') - return result - }, - undefined - ) - return ( -
- - - -
- - - -
- {state && 'error' in state && typeof state.error === 'string' && ( -

{state.error}

- )} -
- ) -} - -function CreateSubmitButton() { - const { pending } = useFormStatus() - return -} - -export function TaskList({ storyId, storyCode, sprintId, productId: _productId, tasks, isDemo }: TaskListProps) { +export function TaskList({ storyId, storyCode, sprintId: _sprintId, productId: _productId, tasks, isDemo }: TaskListProps) { const { taskOrder, initTasks, reorderTasks, rollbackTasks } = useSprintStore() - const [creating, setCreating] = useState(false) const [activeDragId, setActiveDragId] = useState(null) const [, startTransition] = useTransition() + const router = useRouter() + const pathname = usePathname() const idKey = tasks.map(t => t.id).join(',') useEffect(() => { @@ -187,7 +147,7 @@ export function TaskList({ storyId, storyCode, sprintId, productId: _productId, const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), - useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }) + useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }), ) function handleDragEnd(event: DragEndEvent) { @@ -209,11 +169,12 @@ export function TaskList({ storyId, storyCode, sprintId, productId: _productId, }) } - function handleDelete(id: string) { - startTransition(async () => { - const result = await deleteTaskAction(id) - if (result && 'error' in result) toast.error(result.error ?? 'Verwijderen mislukt') - }) + function openCreateDialog() { + router.push(`${pathname}?newTask=1&storyId=${storyId}`) + } + + function openEditDialog(taskId: string) { + router.push(`${pathname}?editTask=${taskId}`) } return ( @@ -224,22 +185,32 @@ export function TaskList({ storyId, storyCode, sprintId, productId: _productId, <> {doneCount}/{orderedTasks.length} klaar - + } />
- {creating && ( - setCreating(false)} /> - )} - - {orderedTasks.length === 0 && !creating ? ( + {orderedTasks.length === 0 ? (

Geen taken voor deze story.

- +
) : ( @@ -258,7 +229,7 @@ export function TaskList({ storyId, storyCode, sprintId, productId: _productId, code={deriveTaskCode(storyCode, idx + 1)} isDemo={isDemo} onStatusToggle={() => handleStatusToggle(task)} - onDelete={() => handleDelete(task.id)} + onEdit={() => openEditDialog(task.id)} /> ))} @@ -266,7 +237,7 @@ export function TaskList({ storyId, storyCode, sprintId, productId: _productId, {activeDragId && taskMap[activeDragId] && (
{taskMap[activeDragId].title}