'use client' import { useState, useTransition, useActionState, useEffect, useRef, useCallback } from 'react' import { useFormStatus } from 'react-dom' import { toast } from 'sonner' import { Button } from '@/components/ui/button' import { DemoTooltip } from '@/components/shared/demo-tooltip' import { Input } from '@/components/ui/input' import { createTodoAction, toggleTodoAction, archiveCompletedTodosAction, promoteTodoToPbiAction, promoteTodoToStoryAction, } from '@/actions/todos' interface Todo { id: string title: string done: boolean created_at: string } interface Pbi { id: string title: string } interface Product { id: string name: string pbis: Pbi[] } interface TodoListProps { todos: Todo[] products: Product[] isDemo: boolean } function QuickInput({ isDemo }: { isDemo: boolean }) { const [, formAction] = useActionState(createTodoAction, undefined) const ref = useRef(null) return (
setTimeout(() => ref.current?.reset(), 0)} className="flex gap-2 mb-6" >
) } function QuickSubmitButton({ isDemo }: { isDemo: boolean }) { const { pending } = useFormStatus() return ( ) } // --- Promote to PBI dialog --- function PromotePbiDialog({ todo, products, onClose, }: { todo: Todo; products: Product[]; onClose: () => void }) { const handleKey = useCallback((e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }, [onClose]) useEffect(() => { document.addEventListener('keydown', handleKey); return () => document.removeEventListener('keydown', handleKey) }, [handleKey]) const [state, formAction] = useActionState( async (_prev: unknown, fd: FormData) => { const result = await promoteTodoToPbiAction(_prev, fd) if (result?.success) { toast.success('Todo gepromoveerd naar PBI'); onClose() } return result }, undefined ) return (

Promoveer naar PBI

Let op: dit kan niet ongedaan worden gemaakt.

{products.length === 0 ? (

Maak eerst een product aan.

) : ( )}
{typeof state?.error === 'string' &&

{state.error}

}
) } // --- Promote to Story dialog --- function PromoteStoryDialog({ todo, products, onClose, }: { todo: Todo; products: Product[]; onClose: () => void }) { const handleKey = useCallback((e: KeyboardEvent) => { if (e.key === 'Escape') onClose() }, [onClose]) useEffect(() => { document.addEventListener('keydown', handleKey); return () => document.removeEventListener('keydown', handleKey) }, [handleKey]) const [selectedProductId, setSelectedProductId] = useState(products[0]?.id ?? '') const selectedProduct = products.find(p => p.id === selectedProductId) const [state, formAction] = useActionState( async (_prev: unknown, fd: FormData) => { const result = await promoteTodoToStoryAction(_prev, fd) if (result?.success) { toast.success('Todo gepromoveerd naar Story'); onClose() } return result }, undefined ) return (

Promoveer naar Story

Let op: dit kan niet ongedaan worden gemaakt.

{products.length === 0 ? (

Maak eerst een product aan.

) : ( )}
{!selectedProduct?.pbis.length ? (

Maak eerst een PBI aan in dit product.

) : ( )}
{typeof state?.error === 'string' &&

{state.error}

}
) } // --- Main list --- export function TodoList({ todos, products, isDemo }: TodoListProps) { const [, startTransition] = useTransition() const [promotePbi, setPromotePbi] = useState(null) const [promoteStory, setPromoteStory] = useState(null) const open = todos.filter(t => !t.done) const done = todos.filter(t => t.done) function handleToggle(id: string, current: boolean) { startTransition(async () => { await toggleTodoAction(id, !current) }) } function handleArchive() { startTransition(async () => { const result = await archiveCompletedTodosAction() if (result && 'error' in result) toast.error(result.error ?? 'Archiveren mislukt') else toast.success('Afgeronde todos gearchiveerd') }) } return (
{todos.length === 0 ? (

Geen todo's. Voeg er een toe hierboven.

) : ( <>
{open.map(todo => (
handleToggle(todo.id, false)} disabled={isDemo} className="w-4 h-4 rounded accent-primary cursor-pointer" /> {todo.title} {!isDemo && (
)}
))} {done.map(todo => (
handleToggle(todo.id, true)} disabled={isDemo} className="w-4 h-4 rounded accent-primary cursor-pointer" /> {todo.title}
))}
{done.length > 0 && !isDemo && (
)} )} {promotePbi && ( setPromotePbi(null)} /> )} {promoteStory && ( setPromoteStory(null)} /> )}
) }