From 9272449f79e1650f490609c2cb023b459ac223f3 Mon Sep 17 00:00:00 2001 From: Punyapal Shah <53343069+MrPunyapal@users.noreply.github.com> Date: Thu, 5 Nov 2026 02:12:37 +0530 Subject: [PATCH] feat: refresh starred commits when restoring browser history --- resources/js/app.tsx | 2 + resources/js/lib/starred-commits-history.ts | 26 ++++++ tests/Unit/StarredCommitsHistory.test.tsx | 87 +++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 resources/js/lib/starred-commits-history.ts create mode 100644 tests/Unit/StarredCommitsHistory.test.tsx diff --git a/resources/js/app.tsx b/resources/js/app.tsx index dacdc2923..5f0b9bb09 100644 --- a/resources/js/app.tsx +++ b/resources/js/app.tsx @@ -25,11 +25,13 @@ import { pageReadAt, } from '@/lib/realtime'; import { registerServiceWorker } from '@/lib/service-worker'; +import { trackStarredCommitsHistory } from '@/lib/starred-commits-history'; import { browserClock, clockOf, setReaderClock } from '@/lib/utils'; import { trackVisualViewport } from '@/lib/visual-viewport'; import '../css/app.css'; trackCurrentPage(); +trackStarredCommitsHistory(); trackCommitPhotoPage(); trackVisualViewport(); trackAnalyticsEvents(); diff --git a/resources/js/lib/starred-commits-history.ts b/resources/js/lib/starred-commits-history.ts new file mode 100644 index 000000000..8ecbae9a0 --- /dev/null +++ b/resources/js/lib/starred-commits-history.ts @@ -0,0 +1,26 @@ +import { router } from '@inertiajs/react'; + +type PhotoBackground = { backgroundUrl?: string }; + +/** Starring or unstarring elsewhere can leave the cached starred list stale. */ +export function trackStarredCommitsHistory(): VoidFunction { + return router.on('navigate', ({ detail: { type, page } }) => { + if (type !== 'history' || page.component !== 'starred/index') { + return; + } + + const photo = page.props.photo as PhotoBackground | undefined; + + queueMicrotask(() => { + // Drop old-cursor pagination requests before resetting the feed. + router.cancelAll({ async: true, prefetch: false, sync: false }); + router.visit(photo?.backgroundUrl ?? page.url, { + only: ['commits'], + reset: ['commits'], + preserveState: true, + preserveScroll: false, + preserveUrl: photo?.backgroundUrl !== undefined, + }); + }); + }); +} diff --git a/tests/Unit/StarredCommitsHistory.test.tsx b/tests/Unit/StarredCommitsHistory.test.tsx new file mode 100644 index 000000000..79022673c --- /dev/null +++ b/tests/Unit/StarredCommitsHistory.test.tsx @@ -0,0 +1,87 @@ +import assert from 'node:assert/strict'; +import { test, vi } from 'vite-plus/test'; + +type NavigationType = 'initial' | 'visit' | 'history'; +type Navigation = { + detail: { + type: NavigationType; + page: { component: string; url: string; props: { photo?: { backgroundUrl: string } } }; + }; +}; + +const visit = vi.fn(); +const cancelAll = vi.fn(); +let navigate: ((event: Navigation) => void) | undefined; + +vi.doMock('@inertiajs/react', () => ({ + router: { + on: (event: string, listener: (event: Navigation) => void) => { + assert.equal(event, 'navigate'); + navigate = listener; + + return () => { + navigate = undefined; + }; + }, + visit, + cancelAll, + }, +})); + +const { trackStarredCommitsHistory } = await import( + '../../resources/js/lib/starred-commits-history' +); + +test('refreshes starred commits after history listeners have completed', async () => { + visit.mockClear(); + cancelAll.mockClear(); + const stop = trackStarredCommitsHistory(); + const go = ( + type: NavigationType, + component: string, + photo?: { backgroundUrl: string }, + url = '/starred', + ) => + navigate?.({ detail: { type, page: { component, url, props: { photo } } } }); + + go('initial', 'starred/index'); + go('visit', 'starred/index'); + go('history', 'log/show'); + assert.equal(visit.mock.calls.length, 0); + + go('history', 'starred/index'); + assert.equal(visit.mock.calls.length, 0); + await Promise.resolve(); + assert.equal(visit.mock.calls.length, 1); + assert.equal(cancelAll.mock.calls.length, 1); + assert.deepEqual(cancelAll.mock.calls[0][0], { + async: true, + prefetch: false, + sync: false, + }); + assert.equal(visit.mock.calls[0][0], '/starred'); + assert.deepEqual(visit.mock.calls[0][1], { + only: ['commits'], + reset: ['commits'], + preserveState: true, + preserveScroll: false, + preserveUrl: false, + }); + + go('history', 'starred/index', { backgroundUrl: '/starred' }, '/post/photo/1'); + assert.equal(visit.mock.calls.length, 1); + await Promise.resolve(); + assert.equal(cancelAll.mock.calls.length, 2); + assert.equal(visit.mock.calls[1][0], '/starred'); + assert.deepEqual(visit.mock.calls[1][1], { + only: ['commits'], + reset: ['commits'], + preserveState: true, + preserveScroll: false, + preserveUrl: true, + }); + + stop(); + go('history', 'starred/index'); + assert.equal(visit.mock.calls.length, 2); +});