fix(gallery): infinite scroll + timeline + jump use tag_id

All three API calls (/api/gallery/scroll, /api/gallery/timeline,
/api/gallery/jump) were still sending the legacy ?tag=<name> param.
Task 10's backend switch silently ignored it, so subsequent scroll
loads and timeline navigation fetched unfiltered content on a
tag-filtered gallery page.

Read tag_id from window.location.search at init and cache it in
state.activeTagId. Use it as ?tag_id=<int> on every subsequent
fetch. state.activeTag (the display string) stays for human-facing
uses elsewhere.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 08:49:44 -04:00
parent 7df508d65e
commit 3b472cf519
+17 -6
View File
@@ -20,7 +20,8 @@
isLoading: false, isLoading: false,
hasMore: true, hasMore: true,
cursor: null, cursor: null,
activeTag: null, activeTag: null, // display string, used for human-facing bits
activeTagId: null, // integer id, authoritative for filter API calls
loadedSections: new Set(), // year_month keys of loaded sections loadedSections: new Set(), // year_month keys of loaded sections
timelineData: [], timelineData: [],
currentVisibleSection: null, currentVisibleSection: null,
@@ -53,6 +54,16 @@
state.activeTag = window.galleryState.activeTag; state.activeTag = window.galleryState.activeTag;
} }
// Read tag_id from the current URL — that's what the backend filtered by
// for the initial render, and what the scroll/timeline/jump APIs now
// expect after the ?tag=<name> -> ?tag_id=<int> switch.
const urlParams = new URLSearchParams(window.location.search);
const tagIdRaw = urlParams.get('tag_id');
if (tagIdRaw) {
const n = parseInt(tagIdRaw, 10);
if (!isNaN(n)) state.activeTagId = n;
}
// Track initially loaded sections // Track initially loaded sections
parseInitialSections(); parseInitialSections();
@@ -93,8 +104,8 @@
if (state.cursor) { if (state.cursor) {
params.set('cursor', state.cursor); params.set('cursor', state.cursor);
} }
if (state.activeTag) { if (state.activeTagId) {
params.set('tag', state.activeTag); params.set('tag_id', String(state.activeTagId));
} }
const response = await fetch(`/api/gallery/scroll?${params}`); const response = await fetch(`/api/gallery/scroll?${params}`);
@@ -289,7 +300,7 @@
// Timeline functions // Timeline functions
async function loadTimeline() { async function loadTimeline() {
try { try {
const params = state.activeTag ? `?tag=${encodeURIComponent(state.activeTag)}` : ''; const params = state.activeTagId ? `?tag_id=${state.activeTagId}` : '';
const response = await fetch(`/api/gallery/timeline${params}`); const response = await fetch(`/api/gallery/timeline${params}`);
const data = await response.json(); const data = await response.json();
@@ -386,8 +397,8 @@
limit: CONFIG.BATCH_SIZE limit: CONFIG.BATCH_SIZE
}); });
if (state.activeTag) { if (state.activeTagId) {
params.set('tag', state.activeTag); params.set('tag_id', String(state.activeTagId));
} }
const response = await fetch(`/api/gallery/jump?${params}`); const response = await fetch(`/api/gallery/jump?${params}`);