diff --git a/client/src/features/book/composables/__tests__/useBookTableShell.spec.ts b/client/src/features/book/composables/__tests__/useBookTableShell.spec.ts index f60e2250c..5585284e2 100644 --- a/client/src/features/book/composables/__tests__/useBookTableShell.spec.ts +++ b/client/src/features/book/composables/__tests__/useBookTableShell.spec.ts @@ -206,7 +206,7 @@ describe('useBookTableShell', () => { handleEditIndividually() expect(mocks.setBookContext).toHaveBeenCalledWith([10, 30], 2) - expect(mocks.routerPush).toHaveBeenCalledWith({ name: 'book-detail', params: { bookId: 10 }, query: { tab: 'details' } }) + expect(mocks.routerPush).toHaveBeenCalledWith({ name: 'book-detail', params: { bookId: 10 }, query: { tab: 'edit' } }) expect(mocks.exitSelectionMode).toHaveBeenCalledOnce() }) diff --git a/client/src/features/book/composables/__tests__/useBookViewContext.spec.ts b/client/src/features/book/composables/__tests__/useBookViewContext.spec.ts index f8cb8238c..33411104e 100644 --- a/client/src/features/book/composables/__tests__/useBookViewContext.spec.ts +++ b/client/src/features/book/composables/__tests__/useBookViewContext.spec.ts @@ -1,4 +1,4 @@ -import { defineComponent, ref } from 'vue' +import { defineComponent, nextTick, ref } from 'vue' import { mount } from '@vue/test-utils' import { afterEach, describe, expect, it, vi } from 'vitest' import type { BookCard } from '@bookorbit/types' @@ -112,6 +112,49 @@ describe('useBookViewContext', () => { expect(loadMore).toHaveBeenCalledTimes(1) }) + it('does not let a deactivated kept-alive source passively clobber the active navigation context', async () => { + const nav = useBookNavigation() + const showSource = ref(true) + const slots = ref([makeBook(1), makeBook(2), makeBook(3)]) + const total = ref(3) + const loadMore = vi.fn<() => Promise>(async () => {}) + + const Source = defineComponent({ + setup() { + useBookViewContext(slots, total, loadMore) + return {} + }, + template: '
', + }) + + const Harness = defineComponent({ + components: { Source }, + setup() { + return { showSource } + }, + template: '', + }) + + const wrapper = mount(Harness) + await nextTick() + + nav.setBookContext([10, 20], 2) + expect(nav.currentIndex(20)).toBe(1) + + showSource.value = false + await nextTick() + + slots.value = [] + total.value = 0 + await nextTick() + + expect(nav.bookIds.value).toEqual([10, 20]) + expect(nav.currentIndex(20)).toBe(1) + expect(nav.total.value).toBe(2) + + wrapper.unmount() + }) + it('reports the absolute slot index after a jump rail loads a far block', async () => { const nav = useBookNavigation() // First block (rows 0-1) plus a far block (rows 5000-5001) loaded; the diff --git a/client/src/features/book/composables/useBookTableShell.ts b/client/src/features/book/composables/useBookTableShell.ts index 7ce557dfb..70affe3b7 100644 --- a/client/src/features/book/composables/useBookTableShell.ts +++ b/client/src/features/book/composables/useBookTableShell.ts @@ -85,7 +85,7 @@ export function useBookTableShell({ books, querySelection }: BookTableShellOptio const orderedIds = books.value.filter((book) => selection.selectedIds.value.has(book.id)).map((book) => book.id) if (orderedIds.length === 0) return setBookContext(orderedIds, orderedIds.length) - router.push({ name: 'book-detail', params: { bookId: orderedIds[0] }, query: { tab: 'details' } }) + router.push({ name: 'book-detail', params: { bookId: orderedIds[0] }, query: { tab: 'edit' } }) selection.exitSelectionMode() } diff --git a/client/src/features/book/composables/useBookViewContext.ts b/client/src/features/book/composables/useBookViewContext.ts index cf96dea8e..87c0d04e8 100644 --- a/client/src/features/book/composables/useBookViewContext.ts +++ b/client/src/features/book/composables/useBookViewContext.ts @@ -1,19 +1,36 @@ -import { onMounted, watch, type Ref } from 'vue' +import { onActivated, onDeactivated, onMounted, watch, type Ref } from 'vue' import { useBookNavigation } from './useBookNavigation' import type { BookSlot } from './useBookWindow' export function useBookViewContext(slots: Ref, total: Ref, loadMore: () => Promise | unknown) { const { setBookSlotContext, registerLoadMore } = useBookNavigation() + let active = true + const syncBookContext = () => { + if (!active) return setBookSlotContext(slots.value, total.value) } watch([slots, total], () => syncBookContext(), { immediate: true }) - onMounted(() => { + function registerContextLoader() { registerLoadMore(async () => { await loadMore() - syncBookContext() + setBookSlotContext(slots.value, total.value) }) + } + + onMounted(() => { + registerContextLoader() + }) + + onActivated(() => { + active = true + registerContextLoader() + syncBookContext() + }) + + onDeactivated(() => { + active = false }) } diff --git a/client/src/views/CollectionView.vue b/client/src/views/CollectionView.vue index 40f04c638..35b9541c1 100644 --- a/client/src/views/CollectionView.vue +++ b/client/src/views/CollectionView.vue @@ -1,5 +1,5 @@