'use client' import { useState, useTransition, useMemo, useEffect, useRef, useCallback } from 'react' import { useActionState } from 'react' import { useFormStatus } from 'react-dom' import { useReactTable, getCoreRowModel, getPaginationRowModel, flexRender, type ColumnDef, type RowSelectionState, type PaginationState, } from '@tanstack/react-table' import { toast } from 'sonner' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Textarea } from '@/components/ui/textarea' import { DemoTooltip } from '@/components/shared/demo-tooltip' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { createTodoAction, updateTodoAction, archiveSelectedTodosAction, promoteTodoToPbiAction, promoteTodoToStoryAction, } from '@/actions/todos' interface Todo { id: string title: string description: string | null done: boolean created_at: string product_id: string | null product_name: string | null } interface Pbi { id: string title: string } interface Product { id: string name: string pbis: Pbi[] } interface TodoListProps { todos: Todo[] products: Product[] isDemo: boolean } // Checkbox with indeterminate support for TanStack row selection function IndeterminateCheckbox({ indeterminate, className, ...props }: React.InputHTMLAttributes & { indeterminate?: boolean }) { const ref = useRef(null) useEffect(() => { if (ref.current) ref.current.indeterminate = indeterminate ?? false }, [indeterminate]) return ( ) } function SaveButton() { 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(todo.product_id ?? 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}

}
) } // --- Detail card --- function TodoCard({ mode, activeTodo, products, isDemo, defaultProductId, onSuccess, onPromotePbi, onPromoteStory, }: { mode: 'idle' | 'create' | 'edit' activeTodo: Todo | null products: Product[] isDemo: boolean defaultProductId: string onSuccess: () => void onPromotePbi: (todo: Todo) => void onPromoteStory: (todo: Todo) => void }) { const [createState, createFormAction] = useActionState(createTodoAction, undefined) const [editState, editFormAction] = useActionState(updateTodoAction, undefined) useEffect(() => { if (createState && 'success' in createState && createState.success) onSuccess() }, [createState, onSuccess]) useEffect(() => { if (editState && 'success' in editState && editState.success) onSuccess() }, [editState, onSuccess]) if (mode === 'idle') { return (

Selecteer een rij of klik op + om te beginnen.

) } if (mode === 'create') { return (

Nieuwe todo