From 0aa0e51daadf43bce10e9f7c6a1da77b97620e06 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 7 Jan 2023 18:23:10 -0800 Subject: [PATCH] Add favoriting from context menu --- .../context-menu/context-menu-items.tsx | 12 ++-- .../context-menu/context-menu-provider.tsx | 59 ++++++++++++++++++- src/renderer/features/shared/index.ts | 2 + .../mutations/create-favorite-mutation.ts | 15 +++++ .../mutations/delete-favorite-mutation.ts | 15 +++++ 5 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 src/renderer/features/shared/mutations/create-favorite-mutation.ts create mode 100644 src/renderer/features/shared/mutations/delete-favorite-mutation.ts diff --git a/src/renderer/features/context-menu/context-menu-items.tsx b/src/renderer/features/context-menu/context-menu-items.tsx index 10d0fcac..8a67f90a 100644 --- a/src/renderer/features/context-menu/context-menu-items.tsx +++ b/src/renderer/features/context-menu/context-menu-items.tsx @@ -5,8 +5,8 @@ export const SONG_CONTEXT_MENU_ITEMS: SetContextMenuItems = [ { id: 'playLast' }, { divider: true, id: 'playNext' }, { disabled: true, id: 'addToPlaylist' }, - { disabled: true, id: 'addToFavorites' }, - { disabled: true, id: 'removeFromFavorites' }, + { id: 'addToFavorites' }, + { id: 'removeFromFavorites' }, { disabled: true, id: 'setRating' }, ]; @@ -15,8 +15,8 @@ export const ALBUM_CONTEXT_MENU_ITEMS: SetContextMenuItems = [ { id: 'playLast' }, { divider: true, id: 'playNext' }, { disabled: true, id: 'addToPlaylist' }, - { disabled: true, id: 'addToFavorites' }, - { disabled: true, id: 'removeFromFavorites' }, + { id: 'addToFavorites' }, + { id: 'removeFromFavorites' }, { disabled: true, id: 'setRating' }, ]; @@ -25,8 +25,8 @@ export const ARTIST_CONTEXT_MENU_ITEMS: SetContextMenuItems = [ { id: 'playLast' }, { divider: true, id: 'playNext' }, { disabled: true, id: 'addToPlaylist' }, - { disabled: true, id: 'addToFavorites' }, - { disabled: true, id: 'removeFromFavorites' }, + { id: 'addToFavorites' }, + { id: 'removeFromFavorites' }, { disabled: true, id: 'setRating' }, ]; diff --git a/src/renderer/features/context-menu/context-menu-provider.tsx b/src/renderer/features/context-menu/context-menu-provider.tsx index e66c27ef..ca431edb 100644 --- a/src/renderer/features/context-menu/context-menu-provider.tsx +++ b/src/renderer/features/context-menu/context-menu-provider.tsx @@ -6,11 +6,11 @@ import { LibraryItem } from '/@/renderer/api/types'; import { ConfirmModal, ContextMenu, ContextMenuButton, Text, toast } from '/@/renderer/components'; import { OpenContextMenuProps, - SetContextMenuItems, useContextMenuEvents, } from '/@/renderer/features/context-menu/events'; import { usePlayQueueAdd } from '/@/renderer/features/player'; import { useDeletePlaylist } from '/@/renderer/features/playlists'; +import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared'; import { Play } from '/@/renderer/types'; type ContextMenuContextProps = { @@ -167,8 +167,61 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => { }); }; + const createFavoriteMutation = useCreateFavorite(); + const deleteFavoriteMutation = useDeleteFavorite(); + const handleAddToFavorites = () => { + if (!ctx.dataNodes) return; + const nodesToFavorite = ctx.dataNodes.filter((item) => !item.data.userFavorite); + createFavoriteMutation.mutate( + { + query: { + id: nodesToFavorite.map((item) => item.data.id), + type: ctx.type, + }, + }, + { + onError: (err) => { + toast.error({ + message: err.message, + title: 'Error adding to favorites', + }); + }, + onSuccess: () => { + for (const node of nodesToFavorite) { + node.setData({ ...node.data, userFavorite: true }); + } + }, + }, + ); + }; + + const handleRemoveFromFavorites = () => { + if (!ctx.dataNodes) return; + const nodesToUnfavorite = ctx.dataNodes.filter((item) => item.data.userFavorite); + + deleteFavoriteMutation.mutate( + { + query: { + id: nodesToUnfavorite.map((item) => item.data.id), + type: ctx.type, + }, + }, + { + onSuccess: () => { + for (const node of nodesToUnfavorite) { + node.setData({ ...node.data, userFavorite: false }); + } + }, + }, + ); + }; + const contextMenuItems = { - addToFavorites: { id: 'addToFavorites', label: 'Add to favorites', onClick: () => {} }, + addToFavorites: { + id: 'addToFavorites', + label: 'Add to favorites', + onClick: handleAddToFavorites, + }, addToPlaylist: { id: 'addToPlaylist', label: 'Add to playlist', onClick: () => {} }, createPlaylist: { id: 'createPlaylist', label: 'Create playlist', onClick: () => {} }, deletePlaylist: { @@ -194,7 +247,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => { removeFromFavorites: { id: 'removeFromFavorites', label: 'Remove from favorites', - onClick: () => {}, + onClick: handleRemoveFromFavorites, }, setRating: { id: 'setRating', label: 'Set rating', onClick: () => {} }, }; diff --git a/src/renderer/features/shared/index.ts b/src/renderer/features/shared/index.ts index 0bed26d0..8417727f 100644 --- a/src/renderer/features/shared/index.ts +++ b/src/renderer/features/shared/index.ts @@ -4,3 +4,5 @@ export * from './components/play-button'; export * from './utils'; export * from './components/library-header'; export * from './components/library-header-bar'; +export * from './mutations/create-favorite-mutation'; +export * from './mutations/delete-favorite-mutation'; diff --git a/src/renderer/features/shared/mutations/create-favorite-mutation.ts b/src/renderer/features/shared/mutations/create-favorite-mutation.ts new file mode 100644 index 00000000..2be51614 --- /dev/null +++ b/src/renderer/features/shared/mutations/create-favorite-mutation.ts @@ -0,0 +1,15 @@ +import { useMutation } from '@tanstack/react-query'; +import { HTTPError } from 'ky'; +import { api } from '/@/renderer/api'; +import { FavoriteArgs, RawFavoriteResponse } from '/@/renderer/api/types'; +import { MutationOptions } from '/@/renderer/lib/react-query'; +import { useCurrentServer } from '/@/renderer/store'; + +export const useCreateFavorite = (options?: MutationOptions) => { + const server = useCurrentServer(); + + return useMutation, null>({ + mutationFn: (args) => api.controller.createFavorite({ ...args, server }), + ...options, + }); +}; diff --git a/src/renderer/features/shared/mutations/delete-favorite-mutation.ts b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts new file mode 100644 index 00000000..b739f948 --- /dev/null +++ b/src/renderer/features/shared/mutations/delete-favorite-mutation.ts @@ -0,0 +1,15 @@ +import { useMutation } from '@tanstack/react-query'; +import { HTTPError } from 'ky'; +import { api } from '/@/renderer/api'; +import { FavoriteArgs, RawFavoriteResponse } from '/@/renderer/api/types'; +import { MutationOptions } from '/@/renderer/lib/react-query'; +import { useCurrentServer } from '/@/renderer/store'; + +export const useDeleteFavorite = (options?: MutationOptions) => { + const server = useCurrentServer(); + + return useMutation, null>({ + mutationFn: (args) => api.controller.deleteFavorite({ ...args, server }), + ...options, + }); +};