fix list filters

This commit is contained in:
jeffvli
2025-12-02 00:11:42 -08:00
parent 4abfbd1973
commit aff7a61bca
26 changed files with 1022 additions and 565 deletions
@@ -1,17 +1,17 @@
import {
parseAsArrayOf,
parseAsBoolean,
parseAsInteger,
parseAsJson,
parseAsString,
useQueryState,
} from 'nuqs';
import { useCallback, useMemo } from 'react';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useSearchParams } from 'react-router';
import { useSearchTermFilter } from '/@/renderer/features/shared/hooks/use-search-term-filter';
import { useSortByFilter } from '/@/renderer/features/shared/hooks/use-sort-by-filter';
import { useSortOrderFilter } from '/@/renderer/features/shared/hooks/use-sort-order-filter';
import { customFiltersSchema, FILTER_KEYS } from '/@/renderer/features/shared/utils';
import { FILTER_KEYS } from '/@/renderer/features/shared/utils';
import {
parseArrayParam,
parseBooleanParam,
parseCustomFiltersParam,
parseIntParam,
setSearchParam,
} from '/@/renderer/utils/query-params';
import { AlbumListSort, SortOrder } from '/@/shared/types/domain-types';
import { ItemListKey } from '/@/shared/types/types';
@@ -25,37 +25,155 @@ export const useAlbumListFilters = () => {
const { searchTerm, setSearchTerm } = useSearchTermFilter('');
const [genreId, setGenreId] = useQueryState(
FILTER_KEYS.ALBUM.GENRE_ID,
parseAsArrayOf(parseAsString),
const [searchParams, setSearchParams] = useSearchParams();
const genreId = useMemo(
() => parseArrayParam(searchParams, FILTER_KEYS.ALBUM.GENRE_ID),
[searchParams],
);
const [albumArtist, setAlbumArtist] = useQueryState(
FILTER_KEYS.ALBUM.ARTIST_IDS,
parseAsArrayOf(parseAsString),
const albumArtist = useMemo(
() => parseArrayParam(searchParams, FILTER_KEYS.ALBUM.ARTIST_IDS),
[searchParams],
);
const [minYear, setMinYear] = useQueryState(FILTER_KEYS.ALBUM.MIN_YEAR, parseAsInteger);
const [maxYear, setMaxYear] = useQueryState(FILTER_KEYS.ALBUM.MAX_YEAR, parseAsInteger);
const [favorite, setFavorite] = useQueryState(FILTER_KEYS.ALBUM.FAVORITE, parseAsBoolean);
const [compilation, setCompilation] = useQueryState(
FILTER_KEYS.ALBUM.COMPILATION,
parseAsBoolean,
const minYear = useMemo(
() => parseIntParam(searchParams, FILTER_KEYS.ALBUM.MIN_YEAR),
[searchParams],
);
const [hasRating, setHasRating] = useQueryState(FILTER_KEYS.ALBUM.HAS_RATING, parseAsBoolean);
const [recentlyPlayed, setRecentlyPlayed] = useQueryState(
FILTER_KEYS.ALBUM.RECENTLY_PLAYED,
parseAsBoolean,
const maxYear = useMemo(
() => parseIntParam(searchParams, FILTER_KEYS.ALBUM.MAX_YEAR),
[searchParams],
);
const [custom, setCustom] = useQueryState(
FILTER_KEYS.ALBUM._CUSTOM,
parseAsJson(customFiltersSchema),
const favorite = useMemo(
() => parseBooleanParam(searchParams, FILTER_KEYS.ALBUM.FAVORITE),
[searchParams],
);
const compilation = useMemo(
() => parseBooleanParam(searchParams, FILTER_KEYS.ALBUM.COMPILATION),
[searchParams],
);
const hasRating = useMemo(
() => parseBooleanParam(searchParams, FILTER_KEYS.ALBUM.HAS_RATING),
[searchParams],
);
const recentlyPlayed = useMemo(
() => parseBooleanParam(searchParams, FILTER_KEYS.ALBUM.RECENTLY_PLAYED),
[searchParams],
);
const custom = useMemo(
() => parseCustomFiltersParam(searchParams, FILTER_KEYS.ALBUM._CUSTOM),
[searchParams],
);
// Use a ref to track the latest custom filters to avoid stale state during batched updates
const customRef = useRef<null | Record<string, any> | undefined>(custom);
useEffect(() => {
customRef.current = custom;
}, [custom]);
const setGenreId = useCallback(
(value: null | string[]) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.GENRE_ID, value), {
replace: true,
});
},
[setSearchParams],
);
const setAlbumArtist = useCallback(
(value: null | string[]) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.ARTIST_IDS, value), {
replace: true,
});
},
[setSearchParams],
);
const setMinYear = useCallback(
(value: null | number) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.MIN_YEAR, value), {
replace: true,
});
},
[setSearchParams],
);
const setMaxYear = useCallback(
(value: null | number) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.MAX_YEAR, value), {
replace: true,
});
},
[setSearchParams],
);
const setFavorite = useCallback(
(value: boolean | null) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.FAVORITE, value), {
replace: true,
});
},
[setSearchParams],
);
const setCompilation = useCallback(
(value: boolean | null) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.COMPILATION, value), {
replace: true,
});
},
[setSearchParams],
);
const setHasRating = useCallback(
(value: boolean | null) => {
setSearchParams((prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.HAS_RATING, value), {
replace: true,
});
},
[setSearchParams],
);
const setRecentlyPlayed = useCallback(
(value: boolean | null) => {
setSearchParams(
(prev) => setSearchParam(prev, FILTER_KEYS.ALBUM.RECENTLY_PLAYED, value),
{
replace: true,
},
);
},
[setSearchParams],
);
const setCustom = useCallback(
(value: null | Record<string, any>) => {
setSearchParams((prev) => {
const previousValue = prev.get(FILTER_KEYS.ALBUM._CUSTOM);
const newCustom = {
...(previousValue ? JSON.parse(previousValue) : {}),
...value,
};
const filteredNewCustom = Object.fromEntries(
Object.entries(newCustom).filter(
([, value]) => value !== null && value !== undefined,
),
);
prev.set(FILTER_KEYS.ALBUM._CUSTOM, JSON.stringify(filteredNewCustom));
return prev;
});
},
[setSearchParams],
);
const clear = useCallback(() => {