upgrade and refactor for react-query v5

This commit is contained in:
jeffvli 2025-11-02 01:16:53 -07:00
parent dd70d30cd3
commit 8115963264
94 changed files with 1650 additions and 1750 deletions

View file

@ -0,0 +1,54 @@
import { queryOptions } from '@tanstack/react-query';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { QueryHookArgs } from '/@/renderer/lib/react-query';
import { getServerById } from '/@/renderer/store';
import { AlbumDetailQuery, AlbumListQuery } from '/@/shared/types/domain-types';
export const albumQueries = {
detail: (args: QueryHookArgs<AlbumDetailQuery>) => {
return queryOptions({
queryFn: ({ signal }) => {
return api.controller.getAlbumDetail({
apiClientProps: { server: getServerById(args.serverId), signal },
query: args.query,
});
},
queryKey: queryKeys.albums.detail(args.serverId, args.query),
...args.options,
});
},
list: (args: QueryHookArgs<AlbumListQuery>) => {
return queryOptions({
queryFn: ({ signal }) => {
return api.controller.getAlbumList({
apiClientProps: { server: getServerById(args.serverId), signal },
query: args.query,
});
},
queryKey: queryKeys.albums.list(
args.serverId,
args.query,
args.query?.artistIds?.length === 1 ? args.query?.artistIds[0] : undefined,
),
...args.options,
});
},
listCount: (args: QueryHookArgs<AlbumListQuery>) => {
return queryOptions({
queryFn: ({ signal }) => {
return api.controller.getAlbumListCount({
apiClientProps: { server: getServerById(args.serverId), signal },
query: args.query,
});
},
queryKey: queryKeys.albums.count(
args.serverId,
args.query,
args.query?.artistIds?.length === 1 ? args.query?.artistIds[0] : undefined,
),
...args.options,
});
},
};

View file

@ -2,6 +2,7 @@ import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/li
import { RowDoubleClickedEvent, RowHeightParams, RowNode } from '@ag-grid-community/core';
import { useSetState } from '@mantine/hooks';
import { useQuery } from '@tanstack/react-query';
import { MutableRefObject, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { generatePath, useParams } from 'react-router';
@ -18,8 +19,7 @@ import {
} from '/@/renderer/components/virtual-table';
import { FullWidthDiscCell } from '/@/renderer/components/virtual-table/cells/full-width-disc-cell';
import { useCurrentSongRowStyles } from '/@/renderer/components/virtual-table/hooks/use-current-song-row-styles';
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import {
useHandleGeneralContextMenu,
useHandleTableContextMenu,
@ -71,7 +71,14 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
const { t } = useTranslation();
const { albumId } = useParams() as { albumId: string };
const server = useCurrentServer();
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
const detailQuery = useQuery(
albumQueries.detail({ query: { id: albumId }, serverId: server.id }),
);
const { data: detail } = useQuery(
albumQueries.detail({ query: { id: albumId }, serverId: server.id }),
);
const cq = useContainerQuery();
const handlePlayQueueAdd = usePlayQueueAdd();
const tableConfig = useTableSettings('albumDetail');
@ -99,7 +106,7 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
);
const songsRowData = useMemo(() => {
if (!detailQuery.data?.songs) {
if (!detail?.songs) {
return [];
}
@ -109,7 +116,7 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
const rowData: (QueueSong | { id: string; name: string })[] = [];
const discTranslated = t('common.disc', { postProcess: 'upperCase' });
for (const song of detailQuery.data.songs) {
for (const song of detail.songs) {
if (song.discNumber !== discNumber || song.discSubtitle !== discSubtitle) {
discNumber = song.discNumber;
discSubtitle = song.discSubtitle;
@ -128,7 +135,7 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
}
return rowData;
}, [detailQuery.data?.songs, t]);
}, [detail?.songs, t]);
const [pagination, setPagination] = useSetState({
artist: 0,
@ -152,29 +159,46 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
[pagination, setPagination],
);
const artistQuery = useAlbumList({
options: {
cacheTime: 1000 * 60,
enabled: detailQuery?.data?.albumArtists[0]?.id !== undefined,
keepPreviousData: true,
staleTime: 1000 * 60,
},
query: {
_custom: {
jellyfin: {
ExcludeItemIds: detailQuery?.data?.id,
const artistQuery = useQuery(
albumQueries.list({
query: {
_custom: {
jellyfin: {
ExcludeItemIds: detail?.id,
},
},
artistIds: detail?.albumArtists.length ? [detail?.albumArtists[0].id] : undefined,
limit: 15,
sortBy: AlbumListSort.YEAR,
sortOrder: SortOrder.DESC,
startIndex: 0,
},
artistIds: detailQuery?.data?.albumArtists.length
? [detailQuery?.data?.albumArtists[0].id]
: undefined,
limit: 15,
sortBy: AlbumListSort.YEAR,
sortOrder: SortOrder.DESC,
startIndex: 0,
},
serverId: server?.id,
});
serverId: server.id,
}),
);
// const artistQuery = useAlbumList({
// options: {
// enabled: detail?.albumArtists[0]?.id !== undefined,
// gcTime: 1000 * 60,
// placeholderData: true,
// },
// query: {
// _custom: {
// jellyfin: {
// ExcludeItemIds: detailQuery?.data?.id,
// },
// },
// artistIds: detailQuery?.data?.albumArtists.length
// ? [detailQuery?.data?.albumArtists[0].id]
// : undefined,
// limit: 15,
// sortBy: AlbumListSort.YEAR,
// sortOrder: SortOrder.DESC,
// startIndex: 0,
// },
// serverId: server?.id,
// });
const relatedAlbumGenresRequest: AlbumListQuery = {
genres: detailQuery.data?.genres.length ? [detailQuery.data.genres[0].id] : undefined,
@ -184,20 +208,21 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
startIndex: 0,
};
const relatedAlbumGenresQuery = useAlbumList({
options: {
cacheTime: 1000 * 60,
enabled: !!detailQuery?.data?.genres?.[0],
queryKey: queryKeys.albums.related(
server?.id || '',
albumId,
relatedAlbumGenresRequest,
),
staleTime: 1000 * 60,
},
query: relatedAlbumGenresRequest,
serverId: server?.id,
});
const relatedAlbumGenresQuery = useQuery(
albumQueries.list({
options: {
enabled: !!detailQuery?.data?.genres?.[0],
gcTime: 1000 * 60,
queryKey: queryKeys.albums.related(
server?.id || '',
albumId,
relatedAlbumGenresRequest,
),
},
query: relatedAlbumGenresRequest,
serverId: server?.id,
}),
);
const carousels = [
{
@ -335,8 +360,8 @@ export const AlbumDetailContent = ({ background, tableRef }: AlbumDetailContentP
: undefined,
}}
loading={
createFavoriteMutation.isLoading ||
deleteFavoriteMutation.isLoading
createFavoriteMutation.isPending ||
deleteFavoriteMutation.isPending
}
onClick={handleFavorite}
size="lg"

View file

@ -1,10 +1,11 @@
import { useQuery } from '@tanstack/react-query';
import { forwardRef, Fragment, Ref, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { generatePath, useParams } from 'react-router';
import { Link } from 'react-router-dom';
import { queryKeys } from '/@/renderer/api/query-keys';
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { LibraryHeader, useSetRating } from '/@/renderer/features/shared';
import { useContainerQuery } from '/@/renderer/hooks';
import { useSongChange } from '/@/renderer/hooks/use-song-change';
@ -30,7 +31,9 @@ export const AlbumDetailHeader = forwardRef(
({ background }: AlbumDetailHeaderProps, ref: Ref<HTMLDivElement>) => {
const { albumId } = useParams() as { albumId: string };
const server = useCurrentServer();
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
const detailQuery = useQuery(
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
);
const cq = useContainerQuery();
const { t } = useTranslation();
@ -146,7 +149,7 @@ export const AlbumDetailHeader = forwardRef(
onChange={handleUpdateRating}
readOnly={
detailQuery?.isFetching ||
updateRatingMutation.isLoading
updateRatingMutation.isPending
}
value={detailQuery?.data?.userRating || 0}
/>

View file

@ -174,15 +174,17 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => {
const queryKey = queryKeys.albums.list(server?.id || '', query, id);
const albums = await queryClient.fetchQuery(queryKey, async ({ signal }) =>
controller.getAlbumList({
apiClientProps: {
server,
signal,
},
query,
}),
);
const albums = await queryClient.fetchQuery({
queryFn: async ({ signal }) =>
controller.getAlbumList({
apiClientProps: {
server,
signal,
},
query,
}),
queryKey,
});
return albums;
},

View file

@ -1,7 +1,7 @@
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { openModal } from '@mantine/modals';
import { useQueryClient } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
import { MouseEvent, MutableRefObject, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@ -14,7 +14,8 @@ import { useListContext } from '/@/renderer/context/list-context';
import { JellyfinAlbumFilters } from '/@/renderer/features/albums/components/jellyfin-album-filters';
import { NavidromeAlbumFilters } from '/@/renderer/features/albums/components/navidrome-album-filters';
import { SubsonicAlbumFilters } from '/@/renderer/features/albums/components/subsonic-album-filters';
import { OrderToggleButton, useMusicFolders } from '/@/renderer/features/shared';
import { OrderToggleButton } from '/@/renderer/features/shared';
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
import { FilterButton } from '/@/renderer/features/shared/components/filter-button';
import { FolderButton } from '/@/renderer/features/shared/components/folder-button';
import { ListConfigMenu } from '/@/renderer/features/shared/components/list-config-menu';
@ -225,7 +226,9 @@ export const AlbumListHeaderFilters = ({
server,
});
const musicFoldersQuery = useMusicFolders({ query: null, serverId: server?.id });
const musicFoldersQuery = useQuery(
sharedQueries.musicFolders({ query: null, serverId: server?.id }),
);
const sortByLabel =
(server?.type &&
@ -288,7 +291,7 @@ export const AlbumListHeaderFilters = ({
};
const handleRefresh = useCallback(() => {
queryClient.invalidateQueries(queryKeys.albums.list(server?.id || ''));
queryClient.invalidateQueries({ queryKey: queryKeys.albums.list(server?.id || '') });
onFilterChange(filter);
}, [filter, onFilterChange, queryClient, server?.id]);

View file

@ -1,11 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { MultiSelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
import { useGenreList } from '/@/renderer/features/genres';
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
import { AlbumListFilter, useListFilterByKey, useListStoreActions } from '/@/renderer/store';
import { Divider } from '/@/shared/components/divider/divider';
import { Group } from '/@/shared/components/group/group';
@ -27,7 +28,7 @@ interface JellyfinAlbumFiltersProps {
disableArtistFilter?: boolean;
onFilterChange: (filters: AlbumListFilter) => void;
pageKey: string;
serverId?: string;
serverId: string;
}
export const JellyfinAlbumFilters = ({
@ -42,19 +43,21 @@ export const JellyfinAlbumFilters = ({
const { setFilter } = useListStoreActions();
// TODO - eventually replace with /items/filters endpoint to fetch genres and tags specific to the selected library
const genreListQuery = useGenreList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
musicFolderId: filter?.musicFolderId,
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const genreListQuery = useQuery(
genresQueries.list({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
musicFolderId: filter?.musicFolderId,
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const genreList = useMemo(() => {
if (!genreListQuery?.data) return [];
@ -64,17 +67,19 @@ export const JellyfinAlbumFilters = ({
}));
}, [genreListQuery.data]);
const tagsQuery = useTagList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
folder: filter?.musicFolderId,
type: LibraryItem.ALBUM,
},
serverId,
});
const tagsQuery = useQuery(
sharedQueries.tags({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
folder: filter?.musicFolderId,
type: LibraryItem.ALBUM,
},
serverId,
}),
);
const selectedTags = useMemo(() => {
return filter?._custom?.jellyfin?.Tags?.split('|');
@ -171,18 +176,20 @@ export const JellyfinAlbumFilters = ({
onFilterChange(updatedFilters);
}, 250);
const albumArtistListQuery = useAlbumArtistList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const albumArtistListQuery = useQuery(
artistsQueries.albumArtistList({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const selectableAlbumArtists = useMemo(() => {
if (!albumArtistListQuery?.data?.items) return [];

View file

@ -1,3 +1,4 @@
import { useQuery } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
import { ChangeEvent, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@ -6,9 +7,9 @@ import {
MultiSelectWithInvalidData,
SelectWithInvalidData,
} from '/@/renderer/components/select-with-invalid-data';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
import { useGenreList } from '/@/renderer/features/genres';
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
import { sharedQueries } from '/@/renderer/features/shared/api/shared-api';
import {
AlbumListFilter,
getServerById,
@ -39,7 +40,7 @@ interface NavidromeAlbumFiltersProps {
disableArtistFilter?: boolean;
onFilterChange: (filters: AlbumListFilter) => void;
pageKey: string;
serverId?: string;
serverId: string;
}
export const NavidromeAlbumFilters = ({
@ -54,18 +55,20 @@ export const NavidromeAlbumFilters = ({
const { setFilter } = useListStoreActions();
const server = getServerById(serverId);
const genreListQuery = useGenreList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const genreListQuery = useQuery(
genresQueries.list({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const genreList = useMemo(() => {
if (!genreListQuery?.data) return [];
@ -90,16 +93,18 @@ export const NavidromeAlbumFilters = ({
onFilterChange(updatedFilters);
}, 250);
const tagsQuery = useTagList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
type: LibraryItem.ALBUM,
},
serverId,
});
const tagsQuery = useQuery(
sharedQueries.tags({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
type: LibraryItem.ALBUM,
},
serverId,
}),
);
const yesNoUndefinedFilters = [
{
@ -199,19 +204,21 @@ export const NavidromeAlbumFilters = ({
onFilterChange(updatedFilters);
}, 500);
const albumArtistListQuery = useAlbumArtistList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
// searchTerm: debouncedSearchTerm,
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const albumArtistListQuery = useQuery(
artistsQueries.albumArtistList({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
// searchTerm: debouncedSearchTerm,
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const selectableAlbumArtists = useMemo(() => {
if (!albumArtistListQuery?.data?.items) return [];

View file

@ -1,10 +1,11 @@
import { useQuery } from '@tanstack/react-query';
import debounce from 'lodash/debounce';
import { ChangeEvent, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { MultiSelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
import { useAlbumArtistList } from '/@/renderer/features/artists/queries/album-artist-list-query';
import { useGenreList } from '/@/renderer/features/genres';
import { artistsQueries } from '/@/renderer/features/artists/api/artists-api';
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
import { AlbumListFilter, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
import { Divider } from '/@/shared/components/divider/divider';
import { Group } from '/@/shared/components/group/group';
@ -26,7 +27,7 @@ interface SubsonicAlbumFiltersProps {
disableArtistFilter?: boolean;
onFilterChange: (filters: AlbumListFilter) => void;
pageKey: string;
serverId?: string;
serverId: string;
}
export const SubsonicAlbumFilters = ({
@ -40,18 +41,20 @@ export const SubsonicAlbumFilters = ({
const { setFilter } = useListStoreActions();
const [albumArtistSearchTerm, setAlbumArtistSearchTerm] = useState<string>('');
const albumArtistListQuery = useAlbumArtistList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const albumArtistListQuery = useQuery(
artistsQueries.albumArtistList({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: AlbumArtistListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const selectableAlbumArtists = useMemo(() => {
if (!albumArtistListQuery?.data?.items) return [];
@ -73,18 +76,20 @@ export const SubsonicAlbumFilters = ({
onFilterChange(updatedFilters);
};
const genreListQuery = useGenreList({
options: {
cacheTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
});
const genreListQuery = useQuery(
genresQueries.list({
options: {
gcTime: 1000 * 60 * 2,
staleTime: 1000 * 60 * 1,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId,
}),
);
const genreList = useMemo(() => {
if (!genreListQuery?.data) return [];

View file

@ -1,22 +0,0 @@
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
import type { AlbumDetailQuery } from '/@/shared/types/domain-types';
import { useQuery } from '@tanstack/react-query';
import { controller } from '/@/renderer/api/controller';
import { queryKeys } from '/@/renderer/api/query-keys';
import { getServerById } from '/@/renderer/store';
export const useAlbumDetail = (args: QueryHookArgs<AlbumDetailQuery>) => {
const { options, query, serverId } = args;
const server = getServerById(serverId);
return useQuery({
queryFn: ({ signal }) => {
if (!server) throw new Error('Server not found');
return controller.getAlbumDetail({ apiClientProps: { server, signal }, query });
},
queryKey: queryKeys.albums.detail(server?.id || '', query),
...options,
});
};

View file

@ -1,32 +0,0 @@
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
import type { AlbumListQuery } from '/@/shared/types/domain-types';
import { useQuery } from '@tanstack/react-query';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { getServerById } from '/@/renderer/store';
export const useAlbumListCount = (args: QueryHookArgs<AlbumListQuery>) => {
const { options, query, serverId } = args;
const server = getServerById(serverId);
return useQuery({
enabled: !!serverId,
queryFn: ({ signal }) => {
if (!server) throw new Error('Server not found');
return api.controller.getAlbumListCount({
apiClientProps: {
server,
signal,
},
query,
});
},
queryKey: queryKeys.albums.count(
serverId || '',
Object.keys(query).length === 0 ? undefined : query,
),
...options,
});
};

View file

@ -1,67 +0,0 @@
import type { QueryHookArgs } from '/@/renderer/lib/react-query';
import type { AlbumListQuery, AlbumListResponse } from '/@/shared/types/domain-types';
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import { api } from '/@/renderer/api';
import { controller } from '/@/renderer/api/controller';
import { queryKeys } from '/@/renderer/api/query-keys';
import { getServerById } from '/@/renderer/store';
export const useAlbumList = (args: QueryHookArgs<AlbumListQuery>) => {
const { options, query, serverId } = args;
const server = getServerById(serverId);
return useQuery({
enabled: !!serverId,
queryFn: ({ signal }) => {
if (!server) throw new Error('Server not found');
return controller.getAlbumList({
apiClientProps: {
server,
signal,
},
query,
});
},
queryKey: queryKeys.albums.list(
serverId || '',
query,
query?.artistIds?.length === 1 ? query?.artistIds[0] : undefined,
),
...options,
});
};
export const useAlbumListInfinite = (args: QueryHookArgs<AlbumListQuery>) => {
const { options, query, serverId } = args;
const server = getServerById(serverId);
return useInfiniteQuery({
enabled: !!serverId,
getNextPageParam: (lastPage: AlbumListResponse | undefined, pages) => {
if (!lastPage?.items) return undefined;
if (lastPage?.items?.length >= (query?.limit || 50)) {
return pages?.length;
}
return undefined;
},
queryFn: ({ pageParam = 0, signal }) => {
if (!server) throw new Error('Server not found');
return api.controller.getAlbumList({
apiClientProps: {
server,
signal,
},
query: {
...query,
limit: query.limit || 50,
startIndex: pageParam * (query.limit || 50),
},
});
},
queryKey: queryKeys.albums.list(server?.id || '', query),
...options,
});
};

View file

@ -1,12 +1,13 @@
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { useQuery } from '@tanstack/react-query';
import { useRef } from 'react';
import { useParams } from 'react-router';
import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { AlbumDetailContent } from '/@/renderer/features/albums/components/album-detail-content';
import { AlbumDetailHeader } from '/@/renderer/features/albums/components/album-detail-header';
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
import { usePlayQueueAdd } from '/@/renderer/features/player';
import { AnimatedPage, LibraryHeaderBar } from '/@/renderer/features/shared';
import { useFastAverageColor } from '/@/renderer/hooks';
@ -22,7 +23,9 @@ const AlbumDetailRoute = () => {
const { albumId } = useParams() as { albumId: string };
const server = useCurrentServer();
const detailQuery = useAlbumDetail({ query: { id: albumId }, serverId: server?.id });
const detailQuery = useQuery(
albumQueries.detail({ query: { id: albumId }, serverId: server?.id }),
);
const { background: backgroundColor, colorId } = useFastAverageColor({
id: albumId,
src: detailQuery.data?.imageUrl,

View file

@ -1,5 +1,6 @@
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { useQuery } from '@tanstack/react-query';
import isEmpty from 'lodash/isEmpty';
import { useCallback, useMemo, useRef } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
@ -8,10 +9,10 @@ import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import { AlbumListContent } from '/@/renderer/features/albums/components/album-list-content';
import { AlbumListHeader } from '/@/renderer/features/albums/components/album-list-header';
import { useAlbumListCount } from '/@/renderer/features/albums/queries/album-list-count-query';
import { useGenreList } from '/@/renderer/features/genres';
import { genresQueries } from '/@/renderer/features/genres/api/genres-api';
import { usePlayQueueAdd } from '/@/renderer/features/player';
import { AnimatedPage } from '/@/renderer/features/shared';
import { queryClient } from '/@/renderer/lib/react-query';
@ -53,18 +54,20 @@ const AlbumListRoute = () => {
key: pageKey,
});
const genreList = useGenreList({
options: {
cacheTime: 1000 * 60 * 60,
enabled: !!genreId,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId: server?.id,
});
const genreList = useQuery(
genresQueries.list({
options: {
enabled: !!genreId,
gcTime: 1000 * 60 * 60,
},
query: {
sortBy: GenreListSort.NAME,
sortOrder: SortOrder.ASC,
startIndex: 0,
},
serverId: server?.id,
}),
);
const genreTitle = useMemo(() => {
if (!genreList.data) return '';
@ -75,16 +78,18 @@ const AlbumListRoute = () => {
return genre?.name;
}, [genreId, genreList.data]);
const itemCountCheck = useAlbumListCount({
options: {
cacheTime: 1000 * 60,
staleTime: 1000 * 60,
},
query: {
...albumListFilter,
},
serverId: server?.id,
});
const itemCountCheck = useQuery(
albumQueries.listCount({
options: {
gcTime: 1000 * 60,
staleTime: 1000 * 60,
},
query: {
...albumListFilter,
},
serverId: server?.id,
}),
);
const itemCount = itemCountCheck.data === null ? undefined : itemCountCheck.data;

View file

@ -183,8 +183,8 @@ const DummyAlbumDetailRoute = () => {
fill: detailQuery?.data?.userFavorite ? 'primary' : undefined,
}}
loading={
createFavoriteMutation.isLoading ||
deleteFavoriteMutation.isLoading
createFavoriteMutation.isPending ||
deleteFavoriteMutation.isPending
}
onClick={handleFavorite}
variant="subtle"