feat: ST-301-ST-312 M3 Sprint Backlog en Sprint Planning

- useSprintStore met sprintStoryOrder/taskOrder (ST-301)
- Sprint aanmaken modal met Sprint Goal validatie (ST-302)
- Sprint Backlog pagina SplitPane layout met Sprint Goal header (ST-303)
- Stories toevoegen aan Sprint via knop in rechterpaneel (ST-304)
- Sprint Backlog volgorde aanpassen via dnd-kit (ST-305)
- Story uit Sprint verwijderen met status terug naar OPEN (ST-306)
- Sprint Planning pagina SplitPane met story selectie (ST-307)
- Taken aanmaken inline in rechterpaneel (ST-308)
- Taak drag-and-drop verticaal met optimistische update (ST-309)
- Taakstatus toggle TO_DO/IN_PROGRESS/DONE met voortgangsindicator (ST-310)
- Taak inline bewerken en verwijderen (ST-311)
- Sprint afronden dialoog met per-story Done/Terug keuze (ST-312)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-04-24 11:51:27 +02:00
parent 4dd62c199c
commit d92e548f88
12 changed files with 1480 additions and 6 deletions

View file

@ -7,6 +7,7 @@ import { SplitPane } from '@/components/split-pane/split-pane'
import { PbiList } from '@/components/backlog/pbi-list'
import { StoryPanel } from '@/components/backlog/story-panel'
import type { Story } from '@/components/backlog/story-panel'
import { StartSprintButton } from '@/components/sprint/start-sprint-button'
import Link from 'next/link'
interface Props {
@ -22,6 +23,10 @@ export default async function ProductBacklogPage({ params }: Props) {
})
if (!product) notFound()
const activeSprint = await prisma.sprint.findFirst({
where: { product_id: id, status: 'ACTIVE' },
})
const pbis = await prisma.pbi.findMany({
where: { product_id: id },
orderBy: [{ priority: 'asc' }, { sort_order: 'asc' }],
@ -60,12 +65,21 @@ export default async function ProductBacklogPage({ params }: Props) {
<p className="text-xs text-muted-foreground mt-0.5">{product.description}</p>
)}
</div>
<Link
href={`/products/${id}/settings`}
className="text-xs text-muted-foreground hover:text-foreground"
>
Instellingen
</Link>
<div className="flex items-center gap-3">
{activeSprint ? (
<Link href={`/products/${id}/sprint`} className="text-xs text-primary hover:underline font-medium">
Sprint actief
</Link>
) : (
!isDemo && <StartSprintButton productId={id} />
)}
<Link
href={`/products/${id}/settings`}
className="text-xs text-muted-foreground hover:text-foreground"
>
Instellingen
</Link>
</div>
</div>
{/* Split pane */}