diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx index 1c236ea0..bff906ca 100644 --- a/src/renderer/features/albums/components/album-detail-content.tsx +++ b/src/renderer/features/albums/components/album-detail-content.tsx @@ -12,7 +12,7 @@ import { ColDef, RowDoubleClickedEvent } from '@ag-grid-community/core'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import { Box, Group, Stack } from '@mantine/core'; import { useSetState } from '@mantine/hooks'; -import { RiHeartLine, RiMoreFill } from 'react-icons/ri'; +import { RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri'; import { useParams } from 'react-router'; import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query'; import { useSongListStore } from '/@/renderer/store'; @@ -23,7 +23,12 @@ import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { useHandleTableContextMenu } from '/@/renderer/features/context-menu'; import { Play } from '/@/renderer/types'; import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items'; -import { PlayButton, PLAY_TYPES } from '/@/renderer/features/shared'; +import { + PlayButton, + PLAY_TYPES, + useCreateFavorite, + useDeleteFavorite, +} from '/@/renderer/features/shared'; import { useAlbumList } from '/@/renderer/features/albums/queries/album-list-query'; import { AlbumListSort, LibraryItem, QueueSong, SortOrder } from '/@/renderer/api/types'; import { usePlayQueueAdd } from '/@/renderer/features/player'; @@ -149,6 +154,29 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { }); }; + const createFavoriteMutation = useCreateFavorite(); + const deleteFavoriteMutation = useDeleteFavorite(); + + const handleFavorite = () => { + if (!detailQuery?.data) return; + + if (detailQuery.data.userFavorite) { + deleteFavoriteMutation.mutate({ + query: { + id: [detailQuery.data.id], + type: LibraryItem.ALBUM, + }, + }); + } else { + createFavoriteMutation.mutate({ + query: { + id: [detailQuery.data.id], + type: LibraryItem.ALBUM, + }, + }); + } + }; + const { intersectRef, tableContainerRef } = useFixedTableHeader(); return ( @@ -164,10 +192,18 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { diff --git a/src/renderer/features/shared/mutations/create-favorite-mutation.ts b/src/renderer/features/shared/mutations/create-favorite-mutation.ts index 5372f11f..ce8e76e5 100644 --- a/src/renderer/features/shared/mutations/create-favorite-mutation.ts +++ b/src/renderer/features/shared/mutations/create-favorite-mutation.ts @@ -1,11 +1,16 @@ -import { useMutation } from '@tanstack/react-query'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { HTTPError } from 'ky'; import { api } from '/@/renderer/api'; -import { FavoriteArgs, LibraryItem, RawFavoriteResponse } from '/@/renderer/api/types'; +import { JFAlbumDetail } from '/@/renderer/api/jellyfin.types'; +import { NDAlbumDetail } from '/@/renderer/api/navidrome.types'; +import { queryKeys } from '/@/renderer/api/query-keys'; +import { SSAlbumDetail } from '/@/renderer/api/subsonic.types'; +import { FavoriteArgs, LibraryItem, RawFavoriteResponse, ServerType } from '/@/renderer/api/types'; import { MutationOptions } from '/@/renderer/lib/react-query'; import { useCurrentServer, useSetAlbumListItemDataById } from '/@/renderer/store'; export const useCreateFavorite = (options?: MutationOptions) => { + const queryClient = useQueryClient(); const server = useCurrentServer(); const setAlbumListData = useSetAlbumListItemDataById(); @@ -18,7 +23,40 @@ export const useCreateFavorite = (options?: MutationOptions) => { setAlbumListData(id, { userFavorite: 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(server?.id || '', { id: variables.query.id[0] }); + const previous = queryClient.getQueryData(queryKey); + + if (previous) { + switch (server?.type) { + case ServerType.NAVIDROME: + queryClient.setQueryData(queryKey, { + ...previous, + starred: true, + }); + break; + case ServerType.SUBSONIC: + queryClient.setQueryData(queryKey, { + ...previous, + starred: true, + }); + break; + case ServerType.JELLYFIN: + queryClient.setQueryData(queryKey, { + ...previous, + UserData: { + ...previous.UserData, + IsFavorite: true, + }, + }); + break; + } + } + } }, + ...options, }); }; diff --git a/src/renderer/features/shared/mutations/delete-favorite-mutation.ts b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts index 3b11d03a..d41f76f0 100644 --- a/src/renderer/features/shared/mutations/delete-favorite-mutation.ts +++ b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts @@ -1,11 +1,16 @@ -import { useMutation } from '@tanstack/react-query'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { HTTPError } from 'ky'; import { api } from '/@/renderer/api'; -import { FavoriteArgs, LibraryItem, RawFavoriteResponse } from '/@/renderer/api/types'; +import { JFAlbumDetail } from '/@/renderer/api/jellyfin.types'; +import { NDAlbumDetail } from '/@/renderer/api/navidrome.types'; +import { queryKeys } from '/@/renderer/api/query-keys'; +import { SSAlbumDetail } from '/@/renderer/api/subsonic.types'; +import { FavoriteArgs, LibraryItem, RawFavoriteResponse, ServerType } from '/@/renderer/api/types'; import { MutationOptions } from '/@/renderer/lib/react-query'; import { useCurrentServer, useSetAlbumListItemDataById } from '/@/renderer/store'; export const useDeleteFavorite = (options?: MutationOptions) => { + const queryClient = useQueryClient(); const server = useCurrentServer(); const setAlbumListData = useSetAlbumListItemDataById(); @@ -18,6 +23,38 @@ export const useDeleteFavorite = (options?: MutationOptions) => { setAlbumListData(id, { userFavorite: 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(server?.id || '', { id: variables.query.id[0] }); + const previous = queryClient.getQueryData(queryKey); + + if (previous) { + switch (server?.type) { + case ServerType.NAVIDROME: + queryClient.setQueryData(queryKey, { + ...previous, + starred: false, + }); + break; + case ServerType.SUBSONIC: + queryClient.setQueryData(queryKey, { + ...previous, + starred: false, + }); + break; + case ServerType.JELLYFIN: + queryClient.setQueryData(queryKey, { + ...previous, + UserData: { + ...previous.UserData, + IsFavorite: false, + }, + }); + break; + } + } + } }, ...options, });