feat(filters): encode downloaded filter in the URL

This commit is contained in:
Darkraise
2026-08-11 18:19:20 +07:00
parent 3cef0feb7c
commit e7bbd36aff
2 changed files with 47 additions and 0 deletions
@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest';
import {
buildFilterSearchParams,
parseFilterParams,
compressFilters,
decompressFilters,
} from './filterUrlCompression';
describe('downloaded filter URL round-trip', () => {
it('round-trips an explicit on', () => {
const encoded = compressFilters({ downloaded: '1' });
expect(encoded).not.toBeNull();
expect(decompressFilters(encoded ?? '')?.downloaded).toBe('1');
});
it('round-trips an explicit off rather than dropping it', () => {
const encoded = compressFilters({ downloaded: '0' });
expect(encoded).not.toBeNull();
expect(decompressFilters(encoded ?? '')?.downloaded).toBe('0');
});
it('survives buildFilterSearchParams and parseFilterParams', () => {
const params = buildFilterSearchParams({ downloaded: '0', search: 'sonic' });
const parsed = parseFilterParams(params);
expect(parsed.downloaded).toBe('0');
expect(parsed.search).toBe('sonic');
});
it('leaves downloaded undefined when absent', () => {
const parsed = parseFilterParams(new URLSearchParams());
expect(parsed.downloaded).toBeUndefined();
});
});
+14
View File
@@ -18,6 +18,8 @@ export interface FilterUrlParams {
sortOrder?: string;
page?: number;
fo?: string; // filter order
/** '1' = downloaded only, '0' = explicitly off, undefined = use the admin default */
downloaded?: '0' | '1';
}
// Filter order category abbreviations
@@ -31,6 +33,7 @@ const CATEGORY_TO_ABBR: Record<string, string> = {
Language: 'L',
Tag: 'T',
Year: 'Y',
Downloaded: 'W',
};
const ABBR_TO_CATEGORY: Record<string, string> = Object.fromEntries(
@@ -104,6 +107,7 @@ function toUrlSafeFormat(params: FilterUrlParams): string | null {
if (params.tags) parts.push(`t.${escapeValue(params.tags)}`);
if (params.yearFrom !== undefined) parts.push(`f.${params.yearFrom}`);
if (params.yearTo !== undefined) parts.push(`e.${params.yearTo}`);
if (params.downloaded !== undefined) parts.push(`w.${params.downloaded}`);
if (params.fo) parts.push(`o.${encodeFilterOrder(params.fo)}`);
// Join with underscore (URL-safe)
@@ -163,6 +167,9 @@ function fromUrlSafeFormat(encoded: string): FilterUrlParams | null {
case 'o':
params.fo = decodeFilterOrder(value);
break;
case 'w':
if (value === '0' || value === '1') params.downloaded = value;
break;
}
}
@@ -367,6 +374,12 @@ export function parseFilterParams(searchParams: URLSearchParams): FilterUrlParam
sortOrder: searchParams.get('sortOrder') ?? undefined,
page: safeParseInt(searchParams.get('page')),
fo: searchParams.get('fo') ?? undefined,
downloaded:
searchParams.get('downloaded') === '1'
? '1'
: searchParams.get('downloaded') === '0'
? '0'
: undefined,
};
}
@@ -413,6 +426,7 @@ export function hasLegacyParams(searchParams: URLSearchParams): boolean {
'yearFrom',
'yearTo',
'fo',
'downloaded',
];
return legacyKeys.some((key) => searchParams.has(key));
}