mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
fix favorite/rating handlers on detail page
This commit is contained in:
@@ -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 (
|
||||
<div className={styles.libraryHeaderMenu}>
|
||||
<Group wrap="nowrap">
|
||||
@@ -156,12 +163,20 @@ export const LibraryHeaderMenu = ({
|
||||
{onShuffle && <WideShuffleButton onClick={onShuffle} />}
|
||||
</Group>
|
||||
<Group gap="sm" wrap="nowrap">
|
||||
{onRating && <Rating onChange={onRating} size="lg" value={rating || 0} />}
|
||||
{onRating && (
|
||||
<Rating
|
||||
onChange={onRating}
|
||||
readOnly={isMutatingRating}
|
||||
size="lg"
|
||||
value={rating || 0}
|
||||
/>
|
||||
)}
|
||||
{onFavorite && (
|
||||
<ActionIcon
|
||||
disabled={isMutatingCreateFavorite || isMutatingDeleteFavorite}
|
||||
icon="favorite"
|
||||
iconProps={{
|
||||
fill: favorite ? 'primary' : undefined,
|
||||
fill: favorite ? 'favorite' : undefined,
|
||||
}}
|
||||
onClick={onFavorite}
|
||||
size="lg"
|
||||
|
||||
@@ -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,23 +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 createFavoriteQueryKey = ['set-favorite', true];
|
||||
|
||||
export const useCreateFavorite = (args: MutationHookArgs) => {
|
||||
const { options } = args || {};
|
||||
const queryClient = useQueryClient();
|
||||
const setAlbumListData = useSetAlbumListItemDataById();
|
||||
// const setQueueFavorite = useSetQueueFavorite();
|
||||
|
||||
const setFavoriteEvent = useFavoriteEvent();
|
||||
|
||||
return useMutation<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
||||
@@ -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<AlbumDetailResponse>(queryKey);
|
||||
|
||||
if (previous) {
|
||||
queryClient.setQueryData<AlbumDetailResponse>(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<AlbumArtistDetailResponse>(queryKey);
|
||||
|
||||
if (previous) {
|
||||
queryClient.setQueryData<AlbumArtistDetailResponse>(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;
|
||||
};
|
||||
|
||||
@@ -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<FavoriteResponse, AxiosError, FavoriteArgs, null>({
|
||||
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<AlbumDetailResponse>(queryKey);
|
||||
|
||||
if (previous) {
|
||||
queryClient.setQueryData<AlbumDetailResponse>(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<AlbumArtistDetailResponse>(queryKey);
|
||||
|
||||
if (previous) {
|
||||
queryClient.setQueryData<AlbumArtistDetailResponse>(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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user