From 7595474fcc6d28fb4e0d62039ec37b468cb1fa86 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Mon, 4 May 2026 21:42:59 +0200 Subject: [PATCH] =?UTF-8?q?ui:=20"=E2=86=92=20Idee"=20promote=20button=20i?= =?UTF-8?q?n=20TodoCard=20+=20PromoteIdeaDialog=20(M12=20T-514)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit components/todos/todo-list.tsx: - TodoCard: new "→ Idee" button next to "→ PBI" + "→ Story" (only shown for non-demo) - PromoteIdeaDialog: confirmation modal — no extra inputs needed since promoteTodoToIdeaAction takes only todoId; title/description carry over from the todo, status starts as DRAFT - onPromoteIdea callback wired through TodoCard props - On success: navigates to /ideas/{new-id} so user lands on the fresh idea-detail page Tests: 546/546 still green. Co-Authored-By: Claude Opus 4.7 (1M context) --- components/todos/todo-list.tsx | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/components/todos/todo-list.tsx b/components/todos/todo-list.tsx index a0022e1..5db21b3 100644 --- a/components/todos/todo-list.tsx +++ b/components/todos/todo-list.tsx @@ -3,6 +3,7 @@ import { useState, useTransition, useMemo, useEffect, useRef, useCallback } from 'react' import { useActionState } from 'react' import { useFormStatus } from 'react-dom' +import { useRouter } from 'next/navigation' import { useReactTable, getCoreRowModel, @@ -26,6 +27,7 @@ import { archiveSelectedTodosAction, promoteTodoToPbiAction, promoteTodoToStoryAction, + promoteTodoToIdeaAction, } from '@/actions/todos' interface Todo { @@ -233,6 +235,60 @@ function PromoteStoryDialog({ ) } +// --- Promote to Idea dialog (M12 T-514) --- +// Geen extra inputs nodig — title/description komen uit de todo, en +// promoteTodoToIdeaAction archiveert de todo automatisch. +function PromoteIdeaDialog({ + todo, + onClose, +}: { todo: Todo; onClose: () => void }) { + const router = useRouter() + const handleKey = useCallback((e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }, [onClose]) + useEffect(() => { + document.addEventListener('keydown', handleKey) + return () => document.removeEventListener('keydown', handleKey) + }, [handleKey]) + + const [pending, startTransition] = useTransition() + + function handleConfirm() { + startTransition(async () => { + const r = await promoteTodoToIdeaAction(todo.id) + if ('error' in r) { + toast.error(r.error) + return + } + toast.success(`Idee aangemaakt (${r.idea_code})`) + onClose() + router.push(`/ideas/${r.idea_id}`) + }) + } + + return ( +
+
+

Promoveer naar Idee

+

+ Maak een nieuw idee van ‘{todo.title}’. De Todo wordt + gearchiveerd; je kunt hem later terugvinden in de archief-filter. +

+

+ Het idee start als DRAFT. Je kunt het daarna grillen, plannen, en + materialiseren tot een PBI. +

+
+ + +
+
+
+ ) +} + // --- Detail card --- function TodoCard({ mode, @@ -243,6 +299,7 @@ function TodoCard({ onSuccess, onPromotePbi, onPromoteStory, + onPromoteIdea, }: { mode: 'idle' | 'create' | 'edit' activeTodo: Todo | null @@ -252,6 +309,7 @@ function TodoCard({ onSuccess: () => void onPromotePbi: (todo: Todo) => void onPromoteStory: (todo: Todo) => void + onPromoteIdea: (todo: Todo) => void }) { const [createState, createFormAction] = useActionState(createTodoAction, undefined) const [editState, editFormAction] = useActionState(updateTodoAction, undefined) @@ -366,6 +424,9 @@ function TodoCard({
{!isDemo && ( <> + @@ -393,6 +454,7 @@ export function TodoList({ todos, products, isDemo }: TodoListProps) { const [mode, setMode] = useState<'idle' | 'create'>('idle') const [promotePbi, setPromotePbi] = useState(null) const [promoteStory, setPromoteStory] = useState(null) + const [promoteIdea, setPromoteIdea] = useState(null) const filtered = useMemo(() => { if (selectedProductId === 'all') return todos @@ -608,6 +670,7 @@ export function TodoList({ todos, products, isDemo }: TodoListProps) { onSuccess={handleCancel} onPromotePbi={setPromotePbi} onPromoteStory={setPromoteStory} + onPromoteIdea={setPromoteIdea} /> {promotePbi && ( @@ -616,6 +679,9 @@ export function TodoList({ todos, products, isDemo }: TodoListProps) { {promoteStory && ( setPromoteStory(null)} /> )} + {promoteIdea && ( + setPromoteIdea(null)} /> + )}
) }