From ac944ed5d299d8eda0f9daff19e6df76e023fd7e Mon Sep 17 00:00:00 2001 From: Scrum4Me Agent <30029041+madhura68@users.noreply.github.com> Date: Wed, 6 May 2026 06:27:21 +0200 Subject: [PATCH] feat(ST-n1csfo4j): handleAllDone + AlertDialog + Alles-op-done knop in sprint-afronden-dialog Voegt handleAllDone toe (roept setAllSprintTasksDoneAction aan en zet alle per-story decisions op DONE in de UI), een bevestigende AlertDialog en een 'Alles op done'-knop bovenaan de story-lijst in de sprint-afronden-dialog. Voegt setAllSprintTasksDoneAction ook toe aan actions/sprints.ts omdat die branch nog niet op main staat. Co-Authored-By: Claude Sonnet 4.6 --- actions/sprints.ts | 29 ++++++++++++++++++ components/sprint/sprint-header.tsx | 46 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/actions/sprints.ts b/actions/sprints.ts index bf7dac3..4b6acbf 100644 --- a/actions/sprints.ts +++ b/actions/sprints.ts @@ -12,6 +12,7 @@ import { updateSprintGoalSchema, } from '@/lib/schemas/sprint' import { enforceUserRateLimit } from '@/lib/rate-limit' +import { updateTaskStatusWithStoryPromotion } from '@/lib/tasks-status-update' async function getSession() { return getIronSession(await cookies(), sessionOptions) @@ -272,3 +273,31 @@ export async function completeSprintAction( revalidatePath(`/products/${sprint.product_id}/sprint`) return { success: true } } + +export async function setAllSprintTasksDoneAction( + sprintId: string, +): Promise<{ ok: true } | { ok: false; error: string }> { + const session = await getSession() + if (!session.userId) return { ok: false, error: 'Niet ingelogd' } + if (session.isDemo) return { ok: false, error: 'Niet beschikbaar in demo-modus' } + + const sprint = await prisma.sprint.findFirst({ + where: { id: sprintId, product: productAccessFilter(session.userId) }, + select: { id: true, product_id: true }, + }) + if (!sprint) return { ok: false, error: 'Sprint niet gevonden' } + + const tasks = await prisma.task.findMany({ + where: { sprint_id: sprintId, product_id: sprint.product_id }, + select: { id: true }, + }) + + await prisma.$transaction(async (tx) => { + for (const task of tasks) { + await updateTaskStatusWithStoryPromotion(task.id, 'DONE', tx) + } + }) + + revalidatePath(`/products/${sprint.product_id}/sprint`) + return { ok: true } +} diff --git a/components/sprint/sprint-header.tsx b/components/sprint/sprint-header.tsx index cee9b20..dac19e4 100644 --- a/components/sprint/sprint-header.tsx +++ b/components/sprint/sprint-header.tsx @@ -114,6 +114,20 @@ export function SprintHeader({ productId, productName, sprint, isDemo, sprintSto }) } + function handleAllDone() { + startSettingAllDone(async () => { + const result = await setAllSprintTasksDoneAction(sprint.id) + if (!result.ok) { + toast.error(result.error ?? 'Alles op done mislukt') + } else { + const allDone: Record = {} + sprintStories.forEach(s => { allDone[s.id] = 'DONE' }) + setDecisions(allDone) + } + setShowAllDoneConfirm(false) + }) + } + return (
@@ -220,6 +234,18 @@ export function SprintHeader({ productId, productName, sprint, isDemo, sprintSto

Geef per story aan wat er mee moet gebeuren:

+
+ +
{sprintStories.map(story => (
@@ -257,6 +283,26 @@ export function SprintHeader({ productId, productName, sprint, isDemo, sprintSto
+ + + + + Alles op done zetten? + + Alle taken én stories in de sprint — inclusief taken met status + REVIEW — worden op DONE gezet. De per-story toggles hieronder + worden daarna bijgewerkt. Je kunt daarna nog per story aanpassen + vóór je de sprint afrondt. + + + + Annuleren + + {isSettingAllDone ? 'Bezig…' : 'Alles op done'} + + + +
) }