1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Update favorite and played state to use Query Invalidation

This commit is contained in:
grafixeyehero 2024-01-31 04:32:54 +03:00
parent 97472ac8bb
commit 31a77c25f3
5 changed files with 79 additions and 59 deletions

View file

@ -18,7 +18,7 @@ const ProgramsSectionView: FC<ProgramsSectionViewProps> = ({
sectionType,
isUpcomingRecordingsEnabled = false
}) => {
const { isLoading, data: sectionsWithItems } = useGetProgramsSectionsWithItems(parentId, sectionType);
const { isLoading, data: sectionsWithItems, refetch } = useGetProgramsSectionsWithItems(parentId, sectionType);
const {
isLoading: isUpcomingRecordingsLoading,
data: upcomingRecordings
@ -60,8 +60,10 @@ const ProgramsSectionView: FC<ProgramsSectionViewProps> = ({
sectionTitle={globalize.translate(section.name)}
items={items ?? []}
url={getRouteUrl(section)}
reloadItems={refetch}
cardOptions={{
...section.cardOptions
...section.cardOptions,
queryKey: ['ProgramSectionWithItems']
}}
/>
@ -73,6 +75,7 @@ const ProgramsSectionView: FC<ProgramsSectionViewProps> = ({
sectionTitle={group.name}
items={group.timerInfo ?? []}
cardOptions={{
queryKey: ['Timers'],
shape: 'overflowBackdrop',
showTitle: true,
showParentTitleOrTitle: true,

View file

@ -102,6 +102,7 @@ const SuggestionsSectionView: FC<SuggestionsSectionViewProps> = ({
url={getRouteUrl(section)}
cardOptions={{
...section.cardOptions,
queryKey: ['SuggestionSectionWithItems'],
showTitle: true,
centerText: true,
cardLayout: false,
@ -117,6 +118,7 @@ const SuggestionsSectionView: FC<SuggestionsSectionViewProps> = ({
sectionTitle={getRecommendationTittle(recommendation)}
items={recommendation.Items ?? []}
cardOptions={{
queryKey: ['MovieRecommendations'],
shape: 'overflowPortrait',
showYear: true,
scalable: true,

View file

@ -1,4 +1,5 @@
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client';
import { useQueryClient } from '@tanstack/react-query';
import React, { FC, useCallback } from 'react';
import CheckIcon from '@mui/icons-material/Check';
import { IconButton } from '@mui/material';
@ -10,28 +11,30 @@ interface PlayedButtonProps {
className?: string;
isPlayed : boolean | undefined;
itemId: string | null | undefined;
itemType: string | null | undefined
itemType: string | null | undefined,
queryKey?: string[]
}
const PlayedButton: FC<PlayedButtonProps> = ({
className,
isPlayed = false,
itemId,
itemType
itemType,
queryKey
}) => {
const queryClient = useQueryClient();
const { mutateAsync: togglePlayedMutation } = useTogglePlayedMutation();
const [playedState, setPlayedState] = React.useState<boolean>(isPlayed);
const getTitle = useCallback(() => {
let buttonTitle;
if (itemType !== BaseItemKind.AudioBook) {
buttonTitle = playedState ? globalize.translate('Watched') : globalize.translate('MarkPlayed');
buttonTitle = isPlayed ? globalize.translate('Watched') : globalize.translate('MarkPlayed');
} else {
buttonTitle = playedState ? globalize.translate('Played') : globalize.translate('MarkPlayed');
buttonTitle = isPlayed ? globalize.translate('Played') : globalize.translate('MarkPlayed');
}
return buttonTitle;
}, [playedState, itemType]);
}, [itemType, isPlayed]);
const onClick = useCallback(async () => {
try {
@ -39,23 +42,29 @@ const PlayedButton: FC<PlayedButtonProps> = ({
throw new Error('Item has no Id');
}
const _isPlayed = await togglePlayedMutation({
await togglePlayedMutation({
itemId,
playedState
isPlayed
},
{ onSuccess: async() => {
await queryClient.invalidateQueries({
queryKey: queryKey,
type: 'all',
refetchType: 'active'
});
setPlayedState(!!_isPlayed);
} });
} catch (e) {
console.error(e);
}
}, [playedState, itemId, togglePlayedMutation]);
}, [itemId, togglePlayedMutation, isPlayed, queryClient, queryKey]);
const btnClass = classNames(
className,
{ 'playstatebutton-played': playedState }
{ 'playstatebutton-played': isPlayed }
);
const iconClass = classNames(
{ 'playstatebutton-icon-played': playedState }
{ 'playstatebutton-icon-played': isPlayed }
);
return (
<IconButton

View file

@ -1,4 +1,5 @@
import React, { FC, useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import FavoriteIcon from '@mui/icons-material/Favorite';
import { IconButton } from '@mui/material';
import classNames from 'classnames';
@ -8,16 +9,18 @@ import globalize from 'scripts/globalize';
interface FavoriteButtonProps {
className?: string;
isFavorite: boolean | undefined;
itemId: string | null | undefined
itemId: string | null | undefined;
queryKey?: string[]
}
const FavoriteButton: FC<FavoriteButtonProps> = ({
className,
isFavorite = false,
itemId
itemId,
queryKey
}) => {
const queryClient = useQueryClient();
const { mutateAsync: toggleFavoriteMutation } = useToggleFavoriteMutation();
const [favoriteState, setFavoriteState] = React.useState<boolean>(isFavorite);
const onClick = useCallback(async () => {
try {
@ -25,28 +28,34 @@ const FavoriteButton: FC<FavoriteButtonProps> = ({
throw new Error('Item has no Id');
}
const _isFavorite = await toggleFavoriteMutation({
await toggleFavoriteMutation({
itemId,
favoriteState
isFavorite
},
{ onSuccess: async() => {
await queryClient.invalidateQueries({
queryKey: queryKey,
type: 'all',
refetchType: 'active'
});
setFavoriteState(!!_isFavorite);
} });
} catch (e) {
console.error(e);
}
}, [favoriteState, itemId, toggleFavoriteMutation]);
}, [isFavorite, itemId, queryClient, queryKey, toggleFavoriteMutation]);
const btnClass = classNames(
className,
{ 'ratingbutton-withrating': favoriteState }
{ 'ratingbutton-withrating': isFavorite }
);
const iconClass = classNames(
{ 'ratingbutton-icon-withrating': favoriteState }
{ 'ratingbutton-icon-withrating': isFavorite }
);
return (
<IconButton
title={favoriteState ? globalize.translate('Favorite') : globalize.translate('AddToFavorites')}
title={isFavorite ? globalize.translate('Favorite') : globalize.translate('AddToFavorites')}
className={btnClass}
size='small'
onClick={onClick}

View file

@ -376,10 +376,12 @@ export const useGetItemsViewByType = (
return useQuery({
queryKey: [
'ItemsViewByType',
{
viewType,
parentId,
itemType,
libraryViewSettings
}
],
queryFn: ({ signal }) =>
fetchGetItemsViewByType(
@ -526,17 +528,17 @@ export const useGetGroupsUpcomingEpisodes = (parentId: ParentId) => {
interface ToggleFavoriteMutationProp {
itemId: string;
favoriteState: boolean
isFavorite: boolean
}
const fetchUpdateFavoriteStatus = async (
currentApi: JellyfinApiContext,
itemId: string,
favoriteState: boolean
isFavorite: boolean
) => {
const { api, user } = currentApi;
if (api && user?.Id) {
if (favoriteState) {
if (isFavorite) {
const response = await getUserLibraryApi(api).unmarkFavoriteItem({
userId: user.Id,
itemId: itemId
@ -555,24 +557,24 @@ const fetchUpdateFavoriteStatus = async (
export const useToggleFavoriteMutation = () => {
const currentApi = useApi();
return useMutation({
mutationFn: ({ itemId, favoriteState }: ToggleFavoriteMutationProp) =>
fetchUpdateFavoriteStatus(currentApi, itemId, favoriteState )
mutationFn: ({ itemId, isFavorite }: ToggleFavoriteMutationProp) =>
fetchUpdateFavoriteStatus(currentApi, itemId, isFavorite )
});
};
interface TogglePlayedMutationProp {
itemId: string;
playedState: boolean
isPlayed: boolean
}
const fetchUpdatePlayedState = async (
currentApi: JellyfinApiContext,
itemId: string,
playedState: boolean
isPlayed: boolean
) => {
const { api, user } = currentApi;
if (api && user?.Id) {
if (playedState) {
if (isPlayed) {
const response = await getPlaystateApi(api).markUnplayedItem({
userId: user.Id,
itemId: itemId
@ -591,8 +593,8 @@ const fetchUpdatePlayedState = async (
export const useTogglePlayedMutation = () => {
const currentApi = useApi();
return useMutation({
mutationFn: ({ itemId, playedState }: TogglePlayedMutationProp) =>
fetchUpdatePlayedState(currentApi, itemId, playedState )
mutationFn: ({ itemId, isPlayed }: TogglePlayedMutationProp) =>
fetchUpdatePlayedState(currentApi, itemId, isPlayed )
});
};
@ -676,7 +678,7 @@ const fetchGetTimers = async (
export const useGetTimers = (isUpcomingRecordingsEnabled: boolean, indexByDate?: boolean) => {
const currentApi = useApi();
return useQuery({
queryKey: ['Timers', isUpcomingRecordingsEnabled, indexByDate],
queryKey: ['Timers', { isUpcomingRecordingsEnabled, indexByDate }],
queryFn: ({ signal }) =>
isUpcomingRecordingsEnabled ? fetchGetTimers(currentApi, indexByDate, { signal }) : []
});
@ -830,7 +832,7 @@ const fetchGetSectionItems = async (
],
parentId: parentId ?? undefined,
imageTypeLimit: 1,
enableImageTypes: [ImageType.Primary],
enableImageTypes: [ImageType.Primary, ImageType.Thumb],
...section.parametersOptions
},
{
@ -882,7 +884,6 @@ const getSectionsWithItems = async (
const updatedSectionWithItems: SectionWithItems[] = [];
for (const section of sections) {
try {
const items = await fetchGetSectionItems(
currentApi, parentId, section, options
);
@ -893,9 +894,6 @@ const getSectionsWithItems = async (
items
});
}
} catch (error) {
console.error(`Error occurred for section ${section.type}: ${error}`);
}
}
return updatedSectionWithItems;
@ -908,7 +906,7 @@ export const useGetSuggestionSectionsWithItems = (
const currentApi = useApi();
const sections = getSuggestionSections();
return useQuery({
queryKey: ['SuggestionSectionWithItems', suggestionSectionType],
queryKey: ['SuggestionSectionWithItems', { suggestionSectionType }],
queryFn: ({ signal }) =>
getSectionsWithItems(currentApi, parentId, sections, suggestionSectionType, { signal }),
enabled: !!parentId
@ -922,9 +920,8 @@ export const useGetProgramsSectionsWithItems = (
const currentApi = useApi();
const sections = getProgramSections();
return useQuery({
queryKey: ['ProgramSectionWithItems', programSectionType],
queryFn: ({ signal }) =>
getSectionsWithItems(currentApi, parentId, sections, programSectionType, { signal })
queryKey: ['ProgramSectionWithItems', { programSectionType }],
queryFn: ({ signal }) => getSectionsWithItems(currentApi, parentId, sections, programSectionType, { signal })
});
};