diff --git a/frontend/src/routes/documents/+page.svelte b/frontend/src/routes/documents/+page.svelte index 22f756d3..80159e25 100644 --- a/frontend/src/routes/documents/+page.svelte +++ b/frontend/src/routes/documents/+page.svelte @@ -36,46 +36,84 @@ let showAdvanced = $state(untrack(hasAdvancedFilters)); let searchTimer: ReturnType; +type FilterSnapshot = { + q: string; + from: string; + to: string; + senderId: string; + receiverId: string; + tags: string[]; + sort: string; + dir: string; + tagQ: string; + tagOp: 'AND' | 'OR'; +}; + +/** + * Builds a URLSearchParams from a filter snapshot. Single source of truth for + * which params the `/documents` URL understands — add a filter here and both + * filter-change nav (triggerSearch) and page nav (buildPageHref) will pick it + * up. `page` is appended only when > 0 so the default page 0 stays out of the + * URL, keeping the filter-change-resets-to-page-0 behaviour implicit. + */ +function buildSearchParams(filters: FilterSnapshot, targetPage?: number): SvelteURLSearchParams { + const params = new SvelteURLSearchParams(); + if (filters.q) params.set('q', filters.q); + if (filters.from) params.set('from', filters.from); + if (filters.to) params.set('to', filters.to); + if (filters.senderId) params.set('senderId', filters.senderId); + if (filters.receiverId) params.set('receiverId', filters.receiverId); + filters.tags.forEach((tag) => params.append('tag', tag)); + if (filters.sort) params.set('sort', filters.sort); + if (filters.dir) params.set('dir', filters.dir); + if (filters.tagQ) params.set('tagQ', filters.tagQ); + if (filters.tagOp === 'OR') params.set('tagOp', 'OR'); + if (targetPage !== undefined && targetPage > 0) params.set('page', String(targetPage)); + return params; +} + /** * Rebuilds the URL from the CURRENT local filter state. `page` is intentionally - * not carried over — any filter change implicitly resets back to page 0, which - * is the expected behaviour. For page-only navigation use {@link buildPageHref} - * instead, which preserves every filter from the server `data`. + * not carried over — any filter change implicitly resets back to page 0. */ function triggerSearch() { - const params = new SvelteURLSearchParams(); - if (q) params.set('q', q); - if (from) params.set('from', from); - if (to) params.set('to', to); - if (senderId) params.set('senderId', senderId); - if (receiverId) params.set('receiverId', receiverId); - tagNames.forEach((tag) => params.append('tag', tag.name)); - if (sort) params.set('sort', sort); - if (dir) params.set('dir', dir); - if (tagQ) params.set('tagQ', tagQ); - if (tagOperator === 'OR') params.set('tagOp', 'OR'); + const params = buildSearchParams({ + q, + from, + to, + senderId, + receiverId, + tags: tagNames.map((t) => t.name), + sort, + dir, + tagQ, + tagOp: tagOperator + }); goto(`/documents?${params.toString()}`, { keepFocus: true, noScroll: true }); } /** - * Builds the href for a Pagination prev/next link. Preserves every current - * filter param and only updates `page`. Uses a normal (not goto) - * so SvelteKit's default scroll restoration brings the user to the top of - * the new slice — the expected behaviour for page navigation. + * Builds the href for a Pagination prev/next link. Preserves every filter + * param from server `data` and updates `page`. Uses a normal (not + * goto) so SvelteKit's default scroll restoration brings the user to the top + * of the new slice — the expected behaviour for page navigation. */ function buildPageHref(targetPage: number): string { - const params = new SvelteURLSearchParams(); - if (data.q) params.set('q', data.q); - if (data.from) params.set('from', data.from); - if (data.to) params.set('to', data.to); - if (data.senderId) params.set('senderId', data.senderId); - if (data.receiverId) params.set('receiverId', data.receiverId); - (data.tags || []).forEach((t: string) => params.append('tag', t)); - if (data.sort) params.set('sort', data.sort); - if (data.dir) params.set('dir', data.dir); - if (data.tagQ) params.set('tagQ', data.tagQ); - if (data.tagOp === 'OR') params.set('tagOp', 'OR'); - if (targetPage > 0) params.set('page', String(targetPage)); + const params = buildSearchParams( + { + q: data.q || '', + from: data.from || '', + to: data.to || '', + senderId: data.senderId || '', + receiverId: data.receiverId || '', + tags: data.tags || [], + sort: data.sort || '', + dir: data.dir || '', + tagQ: data.tagQ || '', + tagOp: (data.tagOp as 'AND' | 'OR') || 'AND' + }, + targetPage + ); const qs = params.toString(); return qs ? `/documents?${qs}` : '/documents'; }