diff --git a/app/(app)/products/[id]/page.tsx b/app/(app)/products/[id]/page.tsx index a428514..a8e79e5 100644 --- a/app/(app)/products/[id]/page.tsx +++ b/app/(app)/products/[id]/page.tsx @@ -3,8 +3,8 @@ import { notFound, redirect } from 'next/navigation' import { getSession } from '@/lib/auth' import { getAccessibleProduct } from '@/lib/product-access' import { prisma } from '@/lib/prisma' -import { pbiStatusToApi, sprintStatusToApi } from '@/lib/task-status' -import { resolveActiveSprint } from '@/lib/active-sprint' +import { pbiStatusToApi } from '@/lib/task-status' +import { getSprintSwitcherData } from '@/lib/sprint-switcher-data' import { BacklogSplitPane } from '@/components/backlog/backlog-split-pane' import { PbiList } from '@/components/backlog/pbi-list' import { StoryPanel } from '@/components/backlog/story-panel' @@ -35,46 +35,12 @@ export default async function ProductBacklogPage({ params, searchParams }: Props const product = await getAccessibleProduct(id, session.userId) if (!product) notFound() - const [allSprints, user, resolvedActiveSprint] = await Promise.all([ - prisma.sprint.findMany({ - where: { product_id: id }, - orderBy: { created_at: 'desc' }, - select: { id: true, code: true, sprint_goal: true, status: true }, - }), + const [user, switcherData] = await Promise.all([ prisma.user.findUnique({ where: { id: session.userId! }, select: { active_product_id: true } }), - resolveActiveSprint(id), + getSprintSwitcherData(id), ]) - const hasOpenSprint = allSprints.some(s => s.status === 'OPEN') - - let buildingSprintIds: string[] = [] - if (allSprints.length > 0) { - const runs = await prisma.sprintRun.findMany({ - where: { - sprint_id: { in: allSprints.map(s => s.id) }, - status: { in: ['QUEUED', 'RUNNING'] }, - }, - select: { sprint_id: true }, - }) - buildingSprintIds = Array.from(new Set(runs.map(r => r.sprint_id))) - } - - const sprintItems = allSprints.map(s => ({ - id: s.id, - code: s.code, - sprint_goal: s.sprint_goal, - status: sprintStatusToApi(s.status), - })) - const activeSprintFromList = resolvedActiveSprint - ? allSprints.find(s => s.id === resolvedActiveSprint.id) - : null - const activeSprintItem = activeSprintFromList - ? { - id: activeSprintFromList.id, - code: activeSprintFromList.code, - sprint_goal: activeSprintFromList.sprint_goal, - status: sprintStatusToApi(activeSprintFromList.status), - } - : null + const { sprintItems, buildingSprintIds, activeSprintItem } = switcherData + const hasOpenSprint = sprintItems.some(s => s.status === 'open') const isActiveProduct = user?.active_product_id === id const pbis = await prisma.pbi.findMany({ diff --git a/app/(app)/products/[id]/solo/page.tsx b/app/(app)/products/[id]/solo/page.tsx index 72aa65b..8af037d 100644 --- a/app/(app)/products/[id]/solo/page.tsx +++ b/app/(app)/products/[id]/solo/page.tsx @@ -2,8 +2,10 @@ import { notFound, redirect } from 'next/navigation' import { getSession } from '@/lib/auth' import { getAccessibleProduct } from '@/lib/product-access' import { prisma } from '@/lib/prisma' +import { getSprintSwitcherData } from '@/lib/sprint-switcher-data' import { SoloBoard } from '@/components/solo/solo-board' import { NoActiveSprint } from '@/components/solo/no-active-sprint' +import { SprintSwitcher } from '@/components/shared/sprint-switcher' import type { SoloTask } from '@/components/solo/solo-board' import type { UnassignedStory } from '@/components/solo/unassigned-stories-sheet' @@ -23,9 +25,23 @@ export default async function SoloProductPage({ params }: Props) { where: { product_id: id, status: 'OPEN' }, }) + const switcherData = await getSprintSwitcherData(id, { activeSprintId: sprint?.id ?? null }) + + const switcherBar = ( +
+ +
+ ) + if (!sprint) { return (
+ {switcherBar}
) @@ -106,14 +122,19 @@ export default async function SoloProductPage({ params }: Props) { })) return ( - +
+ {switcherBar} +
+ +
+
) } diff --git a/app/(app)/products/[id]/sprint/[sprintId]/page.tsx b/app/(app)/products/[id]/sprint/[sprintId]/page.tsx index a079bae..a04849d 100644 --- a/app/(app)/products/[id]/sprint/[sprintId]/page.tsx +++ b/app/(app)/products/[id]/sprint/[sprintId]/page.tsx @@ -6,6 +6,8 @@ import { prisma } from '@/lib/prisma' import { pbiStatusToApi } from '@/lib/task-status' import { SprintBoardClient } from '@/components/sprint/sprint-board-client' import { SyncActiveSprintCookie } from '@/components/sprint/sync-active-sprint-cookie' +import { SprintSwitcher } from '@/components/shared/sprint-switcher' +import { getSprintSwitcherData } from '@/lib/sprint-switcher-data' import { SprintHeader } from '@/components/sprint/sprint-header' import { SprintRunControls } from '@/components/sprint/sprint-run-controls' import { parsePauseContext } from '@/lib/pause-context' @@ -48,6 +50,8 @@ export default async function SprintBoardPage({ params, searchParams }: Props) { }) if (!sprint) notFound() + const switcherData = await getSprintSwitcherData(id, { activeSprintId: sprint.id }) + const activeSprintRun = await prisma.sprintRun.findFirst({ where: { sprint_id: sprint.id, @@ -157,6 +161,14 @@ export default async function SprintBoardPage({ params, searchParams }: Props) { return (
+
+ +
{ + const allSprints = await prisma.sprint.findMany({ + where: { product_id: productId }, + orderBy: { created_at: 'desc' }, + select: { id: true, code: true, sprint_goal: true, status: true }, + }) + + let buildingSprintIds: string[] = [] + if (allSprints.length > 0) { + const runs = await prisma.sprintRun.findMany({ + where: { + sprint_id: { in: allSprints.map(s => s.id) }, + status: { in: ['QUEUED', 'RUNNING'] }, + }, + select: { sprint_id: true }, + }) + buildingSprintIds = Array.from(new Set(runs.map(r => r.sprint_id))) + } + + const sprintItems: SprintSwitcherItem[] = allSprints.map(s => ({ + id: s.id, + code: s.code, + sprint_goal: s.sprint_goal, + status: sprintStatusToApi(s.status), + })) + + let activeSprintItem: SprintSwitcherItem | null = null + if (opts?.activeSprintId !== undefined) { + activeSprintItem = opts.activeSprintId + ? sprintItems.find(s => s.id === opts.activeSprintId) ?? null + : null + } else { + const resolved = await resolveActiveSprint(productId) + activeSprintItem = resolved + ? sprintItems.find(s => s.id === resolved.id) ?? null + : null + } + + return { sprintItems, buildingSprintIds, activeSprintItem } +}