fix: avoid duplicate backlog hydration load
This commit is contained in:
parent
b489e26665
commit
38d99834ef
5 changed files with 47 additions and 8 deletions
|
|
@ -257,6 +257,35 @@ describe('selection cascade', () => {
|
|||
expect(s.relations.taskIdsByStory).toEqual({})
|
||||
expect(s.loading.loadedProductId).toBeNull()
|
||||
})
|
||||
|
||||
it('setActiveProduct kan alleen context zetten zonder full backlog load', () => {
|
||||
useProductWorkspaceStore.getState().hydrateSnapshot(
|
||||
snapshotWith(
|
||||
[makePbi({ id: 'p-1' })],
|
||||
{ 'p-1': [makeStory({ id: 's-1', pbi_id: 'p-1' })] },
|
||||
{ 's-1': [makeTask({ id: 't-1', story_id: 's-1' })] },
|
||||
{ id: 'prod-1', name: 'Product 1' },
|
||||
),
|
||||
)
|
||||
useProductWorkspaceStore.setState((s) => {
|
||||
s.context.activePbiId = 'p-1'
|
||||
s.context.activeStoryId = 's-1'
|
||||
})
|
||||
const fetchSpy = vi.spyOn(globalThis, 'fetch')
|
||||
|
||||
useProductWorkspaceStore
|
||||
.getState()
|
||||
.setActiveProduct(
|
||||
{ id: 'prod-1', name: 'Product 1' },
|
||||
{ load: false, preserveSelection: true },
|
||||
)
|
||||
|
||||
const s = useProductWorkspaceStore.getState()
|
||||
expect(fetchSpy).not.toHaveBeenCalled()
|
||||
expect(s.context.activePbiId).toBe('p-1')
|
||||
expect(s.context.activeStoryId).toBe('s-1')
|
||||
expect(s.entities.pbisById['p-1']).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ export default async function ProductBacklogPage({ params, searchParams }: Props
|
|||
<div className="flex-1 overflow-hidden">
|
||||
<BacklogHydrationWrapper
|
||||
productId={id}
|
||||
productName={product.name}
|
||||
initialData={{
|
||||
pbis: pbis.map((p) => ({ id: p.id, code: p.code, title: p.title, priority: p.priority, sort_order: p.sort_order, description: p.description, created_at: p.created_at, status: pbiStatusToApi(p.status) })),
|
||||
storiesByPbi,
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ export default async function MobileProductBacklogPage({ params, searchParams }:
|
|||
<div className="flex flex-col h-full">
|
||||
<BacklogHydrationWrapper
|
||||
productId={id}
|
||||
productName={product.name}
|
||||
initialData={{
|
||||
pbis: pbis.map((p) => ({ id: p.id, code: p.code, title: p.title, priority: p.priority, sort_order: p.sort_order, description: p.description, created_at: p.created_at, status: pbiStatusToApi(p.status) })),
|
||||
storiesByPbi,
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ import { debugProps } from '@/lib/debug'
|
|||
// De voorganger (stores/product-store.ts) wordt in Story 8 (T-876) verwijderd.
|
||||
export function SetCurrentProduct({ id, name }: { id: string; name: string }) {
|
||||
useEffect(() => {
|
||||
useProductWorkspaceStore.getState().setActiveProduct({ id, name })
|
||||
useProductWorkspaceStore
|
||||
.getState()
|
||||
.setActiveProduct({ id, name }, { load: false, preserveSelection: true })
|
||||
return () => {
|
||||
useProductWorkspaceStore.getState().setActiveProduct(null)
|
||||
useProductWorkspaceStore.getState().setActiveProduct(null, { load: false })
|
||||
}
|
||||
}, [id, name])
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,10 @@ interface State {
|
|||
interface Actions {
|
||||
hydrateSnapshot(snapshot: ProductBacklogSnapshot): void
|
||||
|
||||
setActiveProduct(product: ActiveProduct | null): void
|
||||
setActiveProduct(
|
||||
product: ActiveProduct | null,
|
||||
options?: { load?: boolean; preserveSelection?: boolean },
|
||||
): void
|
||||
setActivePbi(pbiId: string | null): void
|
||||
setActiveStory(storyId: string | null): void
|
||||
setActiveTask(taskId: string | null): void
|
||||
|
|
@ -223,15 +226,18 @@ export const useProductWorkspaceStore = create<ProductWorkspaceStore>()(
|
|||
})
|
||||
},
|
||||
|
||||
setActiveProduct(product) {
|
||||
setActiveProduct(product, options) {
|
||||
const requestId = newRequestId()
|
||||
const productChanged = get().context.activeProduct?.id !== product?.id
|
||||
const shouldResetSelection = productChanged || !options?.preserveSelection
|
||||
|
||||
set((s) => {
|
||||
s.context.activeProduct = product
|
||||
s.context.activePbiId = null
|
||||
s.context.activeStoryId = null
|
||||
s.context.activeTaskId = null
|
||||
if (shouldResetSelection) {
|
||||
s.context.activePbiId = null
|
||||
s.context.activeStoryId = null
|
||||
s.context.activeTaskId = null
|
||||
}
|
||||
s.loading.activeRequestId = requestId
|
||||
|
||||
if (productChanged) {
|
||||
|
|
@ -252,7 +258,7 @@ export const useProductWorkspaceStore = create<ProductWorkspaceStore>()(
|
|||
// selectie kan herstellen. T-857: restore-flow start na ensureProductLoaded.
|
||||
writeProductHint(product?.id ?? null)
|
||||
|
||||
if (product) {
|
||||
if (product && options?.load !== false) {
|
||||
const productId = product.id
|
||||
void (async () => {
|
||||
await get().ensureProductLoaded(productId, requestId)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue