Scrum4Me/app/(app)/insights/tokens/page.tsx
Scrum4Me Agent 51c8a86be4 feat(ST-d9sl8egw): /insights/tokens pagina — sprint-selector, historiek-tabel, dag-grafiek & PBI-aggregaat
Server Component met data-fetching via getSprintTokenHistory/getDayTokenData/
getPbiTokenAggregates. SprintTokenHistoryTable, TokenDayChart (Recharts LineChart),
PbiTokenTable en TokenSelectors (client, URL-params). Link toegevoegd in
insights/page.tsx.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 03:20:53 +02:00

84 lines
3.1 KiB
TypeScript

import { cookies } from 'next/headers'
import { getIronSession } from 'iron-session'
import { SessionData, sessionOptions } from '@/lib/session'
import { prisma } from '@/lib/prisma'
import { productAccessFilter } from '@/lib/product-access'
import { getSprintTokenHistory, getDayTokenData, getPbiTokenAggregates } from '@/lib/insights/token-history'
import { SprintTokenHistoryTable } from './components/sprint-token-history-table'
import { TokenDayChart } from './components/token-day-chart'
import { PbiTokenTable } from './components/pbi-token-table'
import { TokenSelectors } from './components/token-selectors'
interface TokensPageProps {
searchParams: Promise<{ product?: string; sprint?: string }>
}
export default async function TokensPage({ searchParams }: TokensPageProps) {
const session = await getIronSession<SessionData>(await cookies(), sessionOptions)
const userId = session.userId!
const { product: filterProductId, sprint: filterSprintId } = await searchParams
const [sprintHistory, productList, activeSprint, allSprints] = await Promise.all([
getSprintTokenHistory(userId, filterProductId),
prisma.product.findMany({
where: productAccessFilter(userId),
select: { id: true, name: true },
orderBy: { name: 'asc' },
}),
prisma.sprint.findFirst({
where: { status: 'ACTIVE', product: productAccessFilter(userId) },
select: { id: true, sprint_goal: true },
}),
prisma.sprint.findMany({
where: { product: productAccessFilter(userId) },
select: { id: true, sprint_goal: true },
orderBy: { created_at: 'desc' },
take: 20,
}),
])
const selectedSprintId = filterSprintId ?? activeSprint?.id ?? ''
const [dayData, pbiData] = selectedSprintId
? await Promise.all([
getDayTokenData(userId, selectedSprintId),
getPbiTokenAggregates(userId, selectedSprintId),
])
: [[], []]
return (
<div className="p-6 space-y-8 max-w-5xl mx-auto w-full">
<div className="flex items-center justify-between gap-4 flex-wrap">
<h1 className="text-2xl font-semibold text-foreground">Token-gebruik &amp; kosten</h1>
<a href="/insights" className="text-primary text-sm underline">
Terug naar Insights
</a>
</div>
<TokenSelectors
productList={productList}
sprintList={allSprints}
currentProductId={filterProductId}
currentSprintId={selectedSprintId}
/>
{/* Sprint historiek */}
<section className="space-y-3">
<h2 className="text-lg font-medium text-foreground">Sprint-historiek</h2>
<SprintTokenHistoryTable rows={sprintHistory} selectedSprintId={selectedSprintId} />
</section>
{/* Dagelijkse kosten */}
<section className="space-y-3">
<h2 className="text-lg font-medium text-foreground">Dagelijkse kosten</h2>
<TokenDayChart data={dayData} />
</section>
{/* PBI-aggregaat */}
<section className="space-y-3">
<h2 className="text-lg font-medium text-foreground">Per PBI</h2>
<PbiTokenTable rows={pbiData} />
</section>
</div>
)
}