diff --git a/components/Global/components/favorite-button.tsx b/components/Global/components/favorite-button.tsx index 237c4c36..e791abcc 100644 --- a/components/Global/components/favorite-button.tsx +++ b/components/Global/components/favorite-button.tsx @@ -1,18 +1,13 @@ import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models' import React, { useEffect, useState } from 'react' import Icon from '../helpers/icon' -import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api' -import { useMutation, useQuery } from '@tanstack/react-query' +import { useQuery } from '@tanstack/react-query' import { isUndefined } from 'lodash' import { getTokens, Spinner } from 'tamagui' -import Client from '../../../api/client' import { usePlayerContext } from '../../..//player/provider' -import { queryClient } from '../../../constants/query-client' import { QueryKeys } from '../../../enums/query-keys' -import { trigger } from 'react-native-haptic-feedback' import { fetchUserData } from '../../../api/queries/functions/favorites' - -import * as Burnt from 'burnt' +import { useJellifyUserDataContext } from '../../../components/user-data-provider' interface SetFavoriteMutation { item: BaseItemDto @@ -25,73 +20,38 @@ export default function FavoriteButton({ item: BaseItemDto onToggle?: () => void }): React.JSX.Element { - const { nowPlaying, nowPlayingIsFavorite } = usePlayerContext() + usePlayerContext() - const [isFavorite, setIsFavorite] = useState(isFavoriteItem(item)) + const [isFavorite, setFavorite] = useState(isFavoriteItem(item)) - const { data, isFetching, isFetched, refetch } = useQuery({ + const { toggleFavorite } = useJellifyUserDataContext() + + const { data, isFetching, refetch } = useQuery({ queryKey: [QueryKeys.UserData, item.Id!], queryFn: () => fetchUserData(item.Id!), }) - const useSetFavorite = useMutation({ - mutationFn: async (mutation: SetFavoriteMutation) => { - return getUserLibraryApi(Client.api!).markFavoriteItem({ - itemId: mutation.item.Id!, - }) - }, - onSuccess: () => { - Burnt.alert({ - title: `Added favorite`, - duration: 1, - preset: 'heart', - }) - - trigger('notificationSuccess') - - setIsFavorite(true) - onToggle ? onToggle() : {} - - // Force refresh of track user data - queryClient.invalidateQueries({ queryKey: [QueryKeys.UserData, item.Id] }) - }, - }) - - const useRemoveFavorite = useMutation({ - mutationFn: async (mutation: SetFavoriteMutation) => { - return getUserLibraryApi(Client.api!).unmarkFavoriteItem({ - itemId: mutation.item.Id!, - }) - }, - onSuccess: () => { - Burnt.alert({ - title: `Removed favorite`, - duration: 1, - preset: 'done', - }) - - trigger('notificationSuccess') - setIsFavorite(false) - onToggle ? onToggle() : {} - }, - }) - - const toggleFavorite = () => { - if (isFavorite) useRemoveFavorite.mutate({ item }) - else useSetFavorite.mutate({ item }) - } - useEffect(() => { refetch() }, [item]) + useEffect(() => { + if (data) setFavorite(data.IsFavorite ?? false) + }, [data]) + return isFetching && isUndefined(item.UserData) ? ( ) : ( + toggleFavorite(isFavorite, { + item, + setFavorite, + onToggle, + }) + } /> ) } diff --git a/components/jellify.tsx b/components/jellify.tsx index 2432f593..6dbbc659 100644 --- a/components/jellify.tsx +++ b/components/jellify.tsx @@ -8,6 +8,7 @@ import { useColorScheme } from 'react-native' import { PortalProvider } from '@tamagui/portal' import { JellifyProvider, useJellifyContext } from './provider' import { ToastProvider } from '@tamagui/toast' +import { JellifyUserDataProvider } from './user-data-provider' export default function Jellify(): React.JSX.Element { return ( @@ -26,9 +27,11 @@ function App(): React.JSX.Element { const { loggedIn } = useJellifyContext() return loggedIn ? ( - - - + + + + + ) : ( diff --git a/components/user-data-provider.tsx b/components/user-data-provider.tsx new file mode 100644 index 00000000..8527dea0 --- /dev/null +++ b/components/user-data-provider.tsx @@ -0,0 +1,99 @@ +import Client from '../api/client' +import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models' +import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api' +import { useMutation } from '@tanstack/react-query' +import { createContext, ReactNode, SetStateAction, useContext } from 'react' + +import * as Burnt from 'burnt' +import { trigger } from 'react-native-haptic-feedback' +import { queryClient } from '../constants/query-client' +import { QueryKeys } from '../enums/query-keys' + +interface SetFavoriteMutation { + item: BaseItemDto + setFavorite: React.Dispatch> + onToggle?: () => void +} + +interface JellifyUserDataContext { + toggleFavorite: (isFavorite: boolean, mutation: SetFavoriteMutation) => void +} + +const JellifyUserDataContextInitializer = () => { + const useSetFavorite = useMutation({ + mutationFn: async (mutation: SetFavoriteMutation) => { + return getUserLibraryApi(Client.api!).markFavoriteItem({ + itemId: mutation.item.Id!, + }) + }, + onSuccess: ({ data }, { item, setFavorite, onToggle }) => { + Burnt.alert({ + title: `Added favorite`, + duration: 1, + preset: 'heart', + }) + + trigger('notificationSuccess') + + setFavorite(true) + if (onToggle) onToggle() + + // Force refresh of track user data + queryClient.invalidateQueries({ queryKey: [QueryKeys.UserData, item.Id] }) + }, + }) + + const useRemoveFavorite = useMutation({ + mutationFn: async (mutation: SetFavoriteMutation) => { + return getUserLibraryApi(Client.api!).unmarkFavoriteItem({ + itemId: mutation.item.Id!, + }) + }, + onSuccess: ({ data }, { item, setFavorite, onToggle }) => { + Burnt.alert({ + title: `Removed favorite`, + duration: 1, + preset: 'done', + }) + + trigger('notificationSuccess') + setFavorite(false) + + if (onToggle) onToggle() + + // Force refresh of track user data + queryClient.invalidateQueries({ queryKey: [QueryKeys.UserData, item.Id] }) + }, + }) + + const toggleFavorite = (isFavorite: boolean, mutation: SetFavoriteMutation) => + (isFavorite ? useRemoveFavorite : useSetFavorite).mutate(mutation) + + return { + toggleFavorite, + } +} + +const JellifyUserDataContext = createContext({ + toggleFavorite: () => {}, +}) + +export const JellifyUserDataProvider: ({ + children, +}: { + children: ReactNode +}) => React.JSX.Element = ({ children }: { children: ReactNode }) => { + const { toggleFavorite } = JellifyUserDataContextInitializer() + + return ( + + {children} + + ) +} + +export const useJellifyUserDataContext = () => useContext(JellifyUserDataContext)