'use client' import { useState, useTransition, useActionState } from 'react' import { useFormStatus } from 'react-dom' import { Button } from '@/components/ui/button' import { Textarea } from '@/components/ui/textarea' import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { toast } from 'sonner' import { DemoTooltip } from '@/components/shared/demo-tooltip' import { updateSprintGoalAction, completeSprintAction } from '@/actions/sprints' import type { SprintStory } from './sprint-backlog' interface Sprint { id: string sprint_goal: string status: string } interface SprintHeaderProps { productId: string productName: string sprint: Sprint isDemo: boolean sprintStories: SprintStory[] } function SaveGoalButton() { const { pending } = useFormStatus() return {pending ? 'Opslaan…' : 'Opslaan'} } export function SprintHeader({ productId, productName, sprint, isDemo, sprintStories }: SprintHeaderProps) { const [editingGoal, setEditingGoal] = useState(false) const [completeOpen, setCompleteOpen] = useState(false) const [decisions, setDecisions] = useState>({}) const [isCompleting, startCompleting] = useTransition() const [, goalFormAction] = useActionState( async (_prev: unknown, fd: FormData) => { const result = await updateSprintGoalAction(_prev, fd) if (result?.success) { setEditingGoal(false); toast.success('Sprint goal opgeslagen') } else if (result?.error) toast.error(typeof result.error === 'string' ? result.error : 'Opslaan mislukt') return result }, undefined ) function setDecision(storyId: string, value: 'DONE' | 'OPEN') { setDecisions(prev => ({ ...prev, [storyId]: value })) } function handleComplete() { // Default: stories without explicit decision → OPEN const finalDecisions: Record = {} sprintStories.forEach(s => { finalDecisions[s.id] = decisions[s.id] ?? 'OPEN' }) startCompleting(async () => { const result = await completeSprintAction(sprint.id, finalDecisions) if ('error' in result) toast.error(result.error ?? 'Sprint afronden mislukt') else { toast.success('Sprint afgerond'); setCompleteOpen(false) } }) } return ( {productName} › Sprint actief {editingGoal ? ( setEditingGoal(false)}>× ) : ( !isDemo && setEditingGoal(true)} className="text-left mt-0.5 group"> {sprint.sprint_goal} )} setCompleteOpen(true)}> Sprint afronden {/* Complete sprint dialog */} Sprint afronden Geef per story aan wat er mee moet gebeuren: {sprintStories.map(story => ( {story.title} setDecision(story.id, 'DONE')} className={`text-xs px-2 py-1 rounded transition-colors ${(decisions[story.id] ?? 'OPEN') === 'DONE' ? 'bg-status-done/20 text-status-done font-medium' : 'text-muted-foreground hover:bg-surface-container'}`} > Done setDecision(story.id, 'OPEN')} className={`text-xs px-2 py-1 rounded transition-colors ${(decisions[story.id] ?? 'OPEN') === 'OPEN' ? 'bg-status-todo/20 text-status-todo font-medium' : 'text-muted-foreground hover:bg-surface-container'}`} > Terug ))} setCompleteOpen(false)}>Annuleren {isCompleting ? 'Bezig…' : 'Sprint afronden'} ) }
{sprint.sprint_goal}
Geef per story aan wat er mee moet gebeuren: