'use client' // PBI-74 / Story 9: Sprint workspace hydration wrapper. // // Server-component (sprint page) fetcht initial sprint snapshot; deze wrapper // hydreert useSprintWorkspaceStore op client-mount, mount de SSE-hook en de // resync-laag. import { useEffect, useRef } from 'react' import { useSprintRealtime } from '@/lib/realtime/use-sprint-realtime' import { useSprintWorkspaceResync } from '@/lib/realtime/use-sprint-workspace-resync' import { useSprintWorkspaceStore } from '@/stores/sprint-workspace/store' import type { SprintWorkspaceSnapshot, SprintWorkspaceSprint, SprintWorkspaceStory, SprintWorkspaceTask, } from '@/stores/sprint-workspace/types' export interface SprintHydrationData { sprint: SprintWorkspaceSprint stories: SprintWorkspaceStory[] tasksByStory: Record } interface SprintHydrationWrapperProps { initialData: SprintHydrationData productId: string productName?: string children: React.ReactNode } function fingerprint(data: SprintHydrationData): string { const sprintPart = `${data.sprint.id}:${data.sprint.status}` const storyPart = data.stories .map((s) => `${s.id}:${s.status}:${s.sprint_id ?? 'null'}:${s.sort_order}`) .join(',') const taskPart = Object.entries(data.tasksByStory) .flatMap(([, list]) => list.map((t) => `${t.id}:${t.status}:${t.sort_order}`)) .join(',') return `${sprintPart}|${storyPart}|${taskPart}` } function toWorkspaceSnapshot( data: SprintHydrationData, productId: string, productName: string | undefined, ): SprintWorkspaceSnapshot { return { product: { id: productId, name: productName ?? '' }, sprint: data.sprint, stories: data.stories, tasksByStory: data.tasksByStory, } } export function SprintHydrationWrapper({ initialData, productId, productName, children, }: SprintHydrationWrapperProps) { const lastFingerprint = useRef('') useEffect(() => { const fp = fingerprint(initialData) if (fp !== lastFingerprint.current) { lastFingerprint.current = fp useSprintWorkspaceStore .getState() .hydrateSnapshot(toWorkspaceSnapshot(initialData, productId, productName)) // T-880 schaduw-fase: zet activeSprintId zodat selectors meteen werken useSprintWorkspaceStore.setState((s) => { s.context.activeSprintId = initialData.sprint.id s.context.activeProduct = { id: productId, name: productName ?? '' } }) } }, [initialData, productId, productName]) useSprintRealtime(productId) useSprintWorkspaceResync() return <>{children} }