diff --git a/__tests__/app/m-solo-page.test.ts b/__tests__/app/m-solo-page.test.ts new file mode 100644 index 0000000..a464eb2 --- /dev/null +++ b/__tests__/app/m-solo-page.test.ts @@ -0,0 +1,35 @@ +// ST-1138: regressie-vangnet voor mobile solo-page (server component). +import { describe, it, expect } from 'vitest' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' + +const PAGE = resolve(process.cwd(), 'app/(mobile)/m/products/[id]/solo/page.tsx') +const TASK_DETAIL = resolve(process.cwd(), 'components/solo/task-detail-dialog.tsx') + +describe('mobile solo page (ST-1138)', () => { + const src = readFileSync(PAGE, 'utf-8') + + it('hergebruikt SoloBoard zonder content-aanpassingen', () => { + expect(src).toContain('SoloBoard') + expect(src).toContain("from '@/components/solo/solo-board'") + }) + + it('auth via gedeelde requireSession()', () => { + expect(src).toContain("from '@/lib/auth-guard'") + expect(src).toContain('requireSession()') + }) + + it('geeft NoActiveSprint terug als geen actieve sprint (zelfde gedrag als desktop)', () => { + expect(src).toContain('NoActiveSprint') + }) +}) + +describe('TaskDetailDialog erft mobile-fullscreen (ST-1138 T-332 verify-only)', () => { + // Beslissing A: TaskDetailDialog gebruikt entityDialogContentClasses; mobile-classes + // komen automatisch door uit T-317. Dit test bewijst de wiring blijft staan. + const src = readFileSync(TASK_DETAIL, 'utf-8') + + it('rendert DialogContent met entityDialogContentClasses (geen eigen className-override)', () => { + expect(src).toContain('className={entityDialogContentClasses}') + }) +}) diff --git a/app/(mobile)/m/products/[id]/solo/page.tsx b/app/(mobile)/m/products/[id]/solo/page.tsx new file mode 100644 index 0000000..ce8aa19 --- /dev/null +++ b/app/(mobile)/m/products/[id]/solo/page.tsx @@ -0,0 +1,120 @@ +// PBI-11 / ST-1138: Mobile Solo Paneel — wraps de bestaande SoloBoard zonder +// content-aanpassingen. 3-koloms-kanban blijft (overflow-x scrollt zijwaarts). +// TaskDetailDialog krijgt full-screen-mobile via gedeelde +// entityDialogContentClasses (beslissing A in docs/plans/PBI-11-mobile-shell.md; +// ingebouwd via ST-1133/T-317). + +import { notFound } from 'next/navigation' +import { getAccessibleProduct } from '@/lib/product-access' +import { prisma } from '@/lib/prisma' +import { requireSession } from '@/lib/auth-guard' +import { SoloBoard } from '@/components/solo/solo-board' +import { NoActiveSprint } from '@/components/solo/no-active-sprint' +import type { SoloTask } from '@/components/solo/solo-board' +import type { UnassignedStory } from '@/components/solo/unassigned-stories-sheet' + +interface Props { + params: Promise<{ id: string }> +} + +export default async function MobileSoloProductPage({ params }: Props) { + const { id } = await params + const session = await requireSession() + + const product = await getAccessibleProduct(id, session.userId) + if (!product) notFound() + + const sprint = await prisma.sprint.findFirst({ + where: { product_id: id, status: 'ACTIVE' }, + }) + + if (!sprint) { + return ( +