From 78b680f614693f56588c0a5f55863bc897cde2f0 Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Mon, 8 Jan 2024 00:18:53 +0300 Subject: [PATCH] Convert playstatebutton and ratingbuttons to react --- .../emby-playstatebutton/PlayedButton.tsx | 74 +++++++++++++++++++ .../emby-ratingbutton/FavoriteButton.tsx | 59 +++++++++++++++ src/hooks/useFetchItems.ts | 73 ++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 src/elements/emby-playstatebutton/PlayedButton.tsx create mode 100644 src/elements/emby-ratingbutton/FavoriteButton.tsx diff --git a/src/elements/emby-playstatebutton/PlayedButton.tsx b/src/elements/emby-playstatebutton/PlayedButton.tsx new file mode 100644 index 000000000..7524e8355 --- /dev/null +++ b/src/elements/emby-playstatebutton/PlayedButton.tsx @@ -0,0 +1,74 @@ +import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client'; +import React, { FC, useCallback } from 'react'; +import CheckIcon from '@mui/icons-material/Check'; +import { IconButton } from '@mui/material'; +import classNames from 'classnames'; +import globalize from 'scripts/globalize'; +import { useTogglePlayedMutation } from 'hooks/useFetchItems'; + +interface PlayedButtonProps { + className?: string; + playedState : boolean | undefined; + itemId: string | null | undefined; + itemType: string | null | undefined +} + +const PlayedButton: FC = ({ + className, + playedState = false, + itemId, + itemType +}) => { + const { mutateAsync: togglePlayedMutation } = useTogglePlayedMutation(); + const [isPlayed, setIsPlayed] = React.useState( + playedState ?? false + ); + + const getTitle = useCallback(() => { + let buttonTitle; + if (itemType !== BaseItemKind.AudioBook) { + buttonTitle = isPlayed ? globalize.translate('Watched') : globalize.translate('MarkPlayed'); + } else { + buttonTitle = isPlayed ? globalize.translate('Played') : globalize.translate('MarkPlayed'); + } + + return buttonTitle; + }, [isPlayed, itemType]); + + const onClick = useCallback(async () => { + try { + if (!itemId) { + throw new Error('Item has no Id'); + } + + const response = await togglePlayedMutation({ + itemId, + isPlayed + }); + setIsPlayed(response?.Played); + } catch (e) { + console.error(e); + } + }, [isPlayed, itemId, togglePlayedMutation]); + + const btnClass = classNames( + className, + { 'playstatebutton-played': isPlayed } + ); + + const iconClass = classNames( + { 'playstatebutton-icon-played': isPlayed } + ); + return ( + + + + ); +}; + +export default PlayedButton; diff --git a/src/elements/emby-ratingbutton/FavoriteButton.tsx b/src/elements/emby-ratingbutton/FavoriteButton.tsx new file mode 100644 index 000000000..6126c6de8 --- /dev/null +++ b/src/elements/emby-ratingbutton/FavoriteButton.tsx @@ -0,0 +1,59 @@ +import React, { FC, useCallback } from 'react'; +import FavoriteIcon from '@mui/icons-material/Favorite'; +import { IconButton } from '@mui/material'; +import classNames from 'classnames'; +import { useToggleFavoriteMutation } from 'hooks/useFetchItems'; +import globalize from 'scripts/globalize'; + +interface FavoriteButtonProps { + className?: string; + favoriteState: boolean | undefined; + itemId: string | null | undefined +} + +const FavoriteButton: FC = ({ + className, + favoriteState, + itemId +}) => { + const { mutateAsync: toggleFavoriteMutation } = useToggleFavoriteMutation(); + const [isFavorite, setIsFavorite] = React.useState(favoriteState ?? false); + + const onClick = useCallback(async () => { + try { + if (!itemId) { + throw new Error('Item has no Id'); + } + + const response = await toggleFavoriteMutation({ + itemId, + isFavorite + }); + setIsFavorite(response?.IsFavorite); + } catch (e) { + console.error(e); + } + }, [isFavorite, itemId, toggleFavoriteMutation]); + + const btnClass = classNames( + className, + { 'ratingbutton-withrating': isFavorite } + ); + + const iconClass = classNames( + { 'ratingbutton-icon-withrating': isFavorite } + ); + + return ( + + + + ); +}; + +export default FavoriteButton; diff --git a/src/hooks/useFetchItems.ts b/src/hooks/useFetchItems.ts index 6f8580b0b..3b75186ea 100644 --- a/src/hooks/useFetchItems.ts +++ b/src/hooks/useFetchItems.ts @@ -15,6 +15,7 @@ import { getStudiosApi } from '@jellyfin/sdk/lib/utils/api/studios-api'; import { getTvShowsApi } from '@jellyfin/sdk/lib/utils/api/tv-shows-api'; import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api/user-library-api'; import { getPlaylistsApi } from '@jellyfin/sdk/lib/utils/api/playlists-api'; +import { getPlaystateApi } from '@jellyfin/sdk/lib/utils/api/playstate-api'; import { useMutation, useQuery } from '@tanstack/react-query'; import datetime from 'scripts/datetime'; import globalize from 'scripts/globalize'; @@ -621,3 +622,75 @@ export const useGetGroupsUpcomingEpisodes = (parentId: ParentId) => { enabled: !!parentId }); }; + +interface ToggleFavoriteMutationProp { + itemId: string; + isFavorite: boolean | undefined +} + +const fetchUpdateFavoriteStatus = async ( + currentApi: JellyfinApiContext, + itemId: string, + isFavorite: boolean | undefined +) => { + const { api, user } = currentApi; + if (api && user?.Id) { + if (isFavorite) { + const response = await getUserLibraryApi(api).unmarkFavoriteItem({ + userId: user?.Id, + itemId: itemId + }); + return response.data; + } else { + const response = await getUserLibraryApi(api).markFavoriteItem({ + userId: user?.Id, + itemId: itemId + }); + return response.data; + } + } +}; + +export const useToggleFavoriteMutation = () => { + const currentApi = useApi(); + return useMutation({ + mutationFn: ({ itemId, isFavorite }: ToggleFavoriteMutationProp) => + fetchUpdateFavoriteStatus(currentApi, itemId, isFavorite ) + }); +}; + +interface TogglePlayedMutationProp { + itemId: string; + isPlayed: boolean | undefined +} + +const fetchUpdatePlayedState = async ( + currentApi: JellyfinApiContext, + itemId: string, + isPlayed: boolean | undefined +) => { + const { api, user } = currentApi; + if (api && user?.Id) { + if (isPlayed) { + const response = await getPlaystateApi(api).markUnplayedItem({ + userId: user?.Id, + itemId: itemId + }); + return response.data; + } else { + const response = await getPlaystateApi(api).markPlayedItem({ + userId: user?.Id, + itemId: itemId + }); + return response.data; + } + } +}; + +export const useTogglePlayedMutation = () => { + const currentApi = useApi(); + return useMutation({ + mutationFn: ({ itemId, isPlayed }: TogglePlayedMutationProp) => + fetchUpdatePlayedState(currentApi, itemId, isPlayed ) + }); +};