diff --git a/src/renderer/features/shared/components/library-header.tsx b/src/renderer/features/shared/components/library-header.tsx
index 603fd9ba6..e18134f90 100644
--- a/src/renderer/features/shared/components/library-header.tsx
+++ b/src/renderer/features/shared/components/library-header.tsx
@@ -10,6 +10,9 @@ import {
WidePlayButton,
WideShuffleButton,
} from '/@/renderer/features/shared/components/play-button';
+import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
+import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
+import { useIsMutatingRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Center } from '/@/shared/components/center/center';
import { Group } from '/@/shared/components/group/group';
@@ -149,6 +152,10 @@ export const LibraryHeaderMenu = ({
onShuffle,
rating,
}: LibraryHeaderMenuProps) => {
+ const isMutatingRating = useIsMutatingRating();
+ const isMutatingCreateFavorite = useIsMutatingCreateFavorite();
+ const isMutatingDeleteFavorite = useIsMutatingDeleteFavorite();
+
return (
@@ -156,12 +163,20 @@ export const LibraryHeaderMenu = ({
{onShuffle && }
- {onRating && }
+ {onRating && (
+
+ )}
{onFavorite && (
{
const { options } = args || {};
const queryClient = useQueryClient();
- const setAlbumListData = useSetAlbumListItemDataById();
- // const setQueueFavorite = useSetQueueFavorite();
+
const setFavoriteEvent = useFavoriteEvent();
return useMutation({
@@ -32,6 +26,7 @@ export const useCreateFavorite = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
+ mutationKey: createFavoriteQueryKey,
onError: (_error, variables) => {
eventEmitter.emit('USER_FAVORITE', {
favorite: false,
@@ -51,56 +46,61 @@ export const useCreateFavorite = (args: MutationHookArgs) => {
return null;
},
onSuccess: (_data, variables) => {
- const { apiClientProps } = variables;
- const serverId = apiClientProps.serverId;
-
- if (!serverId) return;
-
- for (const id of variables.query.id) {
- // Set the userFavorite property to true for the album in the album list data store
- if (variables.query.type === LibraryItem.ALBUM) {
- setAlbumListData(id, { userFavorite: true });
- }
- }
-
if (variables.query.type === LibraryItem.SONG) {
- remote?.updateFavorite(true, serverId, variables.query.id);
+ remote?.updateFavorite(true, variables.apiClientProps.serverId, variables.query.id);
// setQueueFavorite(variables.query.id, true);
setFavoriteEvent(variables.query.id, true);
}
- // We only need to set if we're already on the album detail page
- if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
- const queryKey = queryKeys.albums.detail(serverId, { id: variables.query.id[0] });
- const previous = queryClient.getQueryData(queryKey);
-
- if (previous) {
- queryClient.setQueryData(queryKey, {
- ...previous,
- userFavorite: true,
+ switch (variables.query.type) {
+ case LibraryItem.ALBUM: {
+ const queryKey = queryKeys.albums.detail(variables.apiClientProps.serverId);
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
});
+
+ break;
}
- }
+ case LibraryItem.ALBUM_ARTIST: {
+ const queryKey = queryKeys.albumArtists.detail(
+ variables.apiClientProps.serverId,
+ );
- // We only need to set if we're already on the album detail page
- if (
- variables.query.type === LibraryItem.ALBUM_ARTIST &&
- variables.query.id.length === 1
- ) {
- const queryKey = queryKeys.albumArtists.detail(serverId, {
- id: variables.query.id[0],
- });
-
- const previous = queryClient.getQueryData(queryKey);
-
- if (previous) {
- queryClient.setQueryData(queryKey, {
- ...previous,
- userFavorite: true,
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
});
+
+ break;
+ }
+ case LibraryItem.ARTIST: {
+ const queryKey = queryKeys.artists.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ case LibraryItem.SONG: {
+ const queryKey = queryKeys.songs.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
}
}
},
...options,
});
};
+
+export const useIsMutatingCreateFavorite = () => {
+ const mutatingCount = useIsMutating({ mutationKey: createFavoriteQueryKey });
+ return mutatingCount > 0;
+};
diff --git a/src/renderer/features/shared/mutations/delete-favorite-mutation.ts b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts
index 02cc80ee0..087dcea6f 100644
--- a/src/renderer/features/shared/mutations/delete-favorite-mutation.ts
+++ b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts
@@ -1,4 +1,4 @@
-import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useIsMutating, useMutation, useQueryClient } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import isElectron from 'is-electron';
@@ -6,25 +6,17 @@ import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { eventEmitter } from '/@/renderer/events/event-emitter';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
-import { useSetAlbumListItemDataById } from '/@/renderer/store';
import { useFavoriteEvent } from '/@/renderer/store/event.store';
-import {
- AlbumArtistDetailResponse,
- AlbumDetailResponse,
- FavoriteArgs,
- FavoriteResponse,
- LibraryItem,
-} from '/@/shared/types/domain-types';
+import { FavoriteArgs, FavoriteResponse, LibraryItem } from '/@/shared/types/domain-types';
const remote = isElectron() ? window.api.remote : null;
+const deleteFavoriteQueryKey = ['set-favorite', false];
+
export const useDeleteFavorite = (args: MutationHookArgs) => {
const { options } = args || {};
const queryClient = useQueryClient();
- const setAlbumListData = useSetAlbumListItemDataById();
- // const setQueueFavorite = useSetQueueFavorite();
const setFavoriteEvent = useFavoriteEvent();
-
return useMutation({
mutationFn: (args) => {
return api.controller.deleteFavorite({
@@ -32,6 +24,7 @@ export const useDeleteFavorite = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
+ mutationKey: deleteFavoriteQueryKey,
onError: (_error, variables) => {
eventEmitter.emit('USER_FAVORITE', {
favorite: true,
@@ -51,55 +44,64 @@ export const useDeleteFavorite = (args: MutationHookArgs) => {
return null;
},
onSuccess: (_data, variables) => {
- const { apiClientProps } = variables;
- const serverId = apiClientProps.serverId;
-
- for (const id of variables.query.id) {
- // Set the userFavorite property to false for the album in the album list data store
- if (variables.query.type === LibraryItem.ALBUM) {
- setAlbumListData(id, { userFavorite: false });
- }
- }
-
if (variables.query.type === LibraryItem.SONG) {
- remote?.updateFavorite(false, serverId, variables.query.id);
- // setQueueFavorite(variables.query.id, false);
+ remote?.updateFavorite(
+ false,
+ variables.apiClientProps.serverId,
+ variables.query.id,
+ );
setFavoriteEvent(variables.query.id, false);
}
- // We only need to set if we're already on the album detail page
- if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
- const queryKey = queryKeys.albums.detail(serverId, {
- id: variables.query.id[0],
- });
- const previous = queryClient.getQueryData(queryKey);
-
- if (previous) {
- queryClient.setQueryData(queryKey, {
- ...previous,
- userFavorite: false,
+ switch (variables.query.type) {
+ case LibraryItem.ALBUM: {
+ const queryKey = queryKeys.albums.detail(variables.apiClientProps.serverId);
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
});
+
+ break;
}
- }
+ case LibraryItem.ALBUM_ARTIST: {
+ const queryKey = queryKeys.albumArtists.detail(
+ variables.apiClientProps.serverId,
+ );
- // We only need to set if we're already on the album artist detail page
- if (
- variables.query.type === LibraryItem.ALBUM_ARTIST &&
- variables.query.id.length === 1
- ) {
- const queryKey = queryKeys.albumArtists.detail(serverId, {
- id: variables.query.id[0],
- });
- const previous = queryClient.getQueryData(queryKey);
-
- if (previous) {
- queryClient.setQueryData(queryKey, {
- ...previous,
- userFavorite: false,
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
});
+
+ break;
+ }
+ case LibraryItem.ARTIST: {
+ const queryKey = queryKeys.artists.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ case LibraryItem.SONG: {
+ const queryKey = queryKeys.songs.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
}
}
},
...options,
});
};
+
+export const useIsMutatingDeleteFavorite = () => {
+ const mutatingCount = useIsMutating({ mutationKey: deleteFavoriteQueryKey });
+ return mutatingCount > 0;
+};
diff --git a/src/renderer/features/shared/mutations/set-rating-mutation.ts b/src/renderer/features/shared/mutations/set-rating-mutation.ts
index 309dec7f0..71b336bfe 100644
--- a/src/renderer/features/shared/mutations/set-rating-mutation.ts
+++ b/src/renderer/features/shared/mutations/set-rating-mutation.ts
@@ -1,13 +1,17 @@
-import { useMutation } from '@tanstack/react-query';
+import { useIsMutating, useMutation, useQueryClient } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
+import { queryKeys } from '/@/renderer/api/query-keys';
import { eventEmitter } from '/@/renderer/events/event-emitter';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LibraryItem, RatingResponse, SetRatingArgs } from '/@/shared/types/domain-types';
+const setRatingQueryKey = ['set-rating'];
+
export const useSetRating = (args: MutationHookArgs) => {
const { options } = args || {};
+ const queryClient = useQueryClient();
return useMutation<
RatingResponse,
@@ -21,7 +25,8 @@ export const useSetRating = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
- onSuccess: (_data, variables) => {
+ mutationKey: setRatingQueryKey,
+ onError: (_error, variables) => {
eventEmitter.emit('USER_RATING', {
id: variables.query.id,
itemType: variables.query.type,
@@ -29,6 +34,66 @@ export const useSetRating = (args: MutationHookArgs) => {
serverId: variables.apiClientProps.serverId,
});
},
+ onMutate: (variables) => {
+ eventEmitter.emit('USER_RATING', {
+ id: variables.query.id,
+ itemType: variables.query.type,
+ rating: variables.query.rating,
+ serverId: variables.apiClientProps.serverId,
+ });
+
+ return { previous: undefined };
+ },
+ onSuccess: (_data, variables) => {
+ switch (variables.query.type) {
+ case LibraryItem.ALBUM: {
+ const queryKey = queryKeys.albums.detail(variables.apiClientProps.serverId);
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ case LibraryItem.ALBUM_ARTIST: {
+ const queryKey = queryKeys.albumArtists.detail(
+ variables.apiClientProps.serverId,
+ );
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ case LibraryItem.ARTIST: {
+ const queryKey = queryKeys.artists.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ case LibraryItem.SONG: {
+ const queryKey = queryKeys.songs.detail(variables.apiClientProps.serverId);
+
+ queryClient.invalidateQueries({
+ exact: false,
+ queryKey,
+ });
+
+ break;
+ }
+ }
+ },
...options,
});
};
+
+export const useIsMutatingRating = () => {
+ const mutatingCount = useIsMutating({ mutationKey: setRatingQueryKey });
+ return mutatingCount > 0;
+};
diff --git a/src/renderer/lib/react-query.ts b/src/renderer/lib/react-query.ts
index 08e3f4cdb..13b964d12 100644
--- a/src/renderer/lib/react-query.ts
+++ b/src/renderer/lib/react-query.ts
@@ -20,14 +20,13 @@ const queryCache = new QueryCache({
const queryConfig: DefaultOptions = {
mutations: {
- gcTime: 1000 * 20, // 20 seconds
retry: process.env.NODE_ENV === 'production',
},
queries: {
gcTime: 1000 * 5, // 5 seconds
refetchOnWindowFocus: false,
retry: process.env.NODE_ENV === 'production',
- staleTime: 1000 * 5, // 5 seconds
+ staleTime: 0, // 5 seconds
throwOnError: (error: any) => {
return error?.response?.status >= 500;
},