feat(filters): encode downloaded filter in the URL
This commit is contained in:
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user