Invalidated queries when liking and unliking objects

This gives us some live-ness in the frontend, so that when you unlike an item
in the liked view - it will be removed from the list, and the count will be
updated.
This commit is contained in:
Fabien O'Carroll 2024-09-06 11:46:45 +07:00 committed by Fabien 'egg' O'Carroll
parent bd66efa70a
commit 2749296fea
2 changed files with 79 additions and 3 deletions

View File

@ -146,10 +146,11 @@ const FeedItemStats: React.FC<{
} else {
unlikeMutation.mutate(object.id);
}
setIsLiked(!isLiked);
setIsClicked(false); // Reset the animation class after request completed
// Call the requested `onLikeClick`
onLikeClick();
setTimeout(() => setIsClicked(false), 300);

View File

@ -1,6 +1,6 @@
import {ActivityPubAPI} from '../api/activitypub';
import {useBrowseSite} from '@tryghost/admin-x-framework/api/site';
import {useMutation, useQuery} from '@tanstack/react-query';
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
const useSiteUrl = () => {
const site = useBrowseSite();
@ -27,21 +27,96 @@ export function useLikedForUser(handle: string) {
}
export function useLikeMutationForUser(handle: string) {
const queryClient = useQueryClient();
const siteUrl = useSiteUrl();
const api = createActivityPubAPI(handle, siteUrl);
return useMutation({
mutationFn(id: string) {
return api.like(id);
},
onMutate: (id) => {
const previousInbox = queryClient.getQueryData([`inbox:${handle}`]);
if (previousInbox) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryClient.setQueryData([`inbox:${handle}`], (old?: any[]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return old?.map((item: any) => {
if (item.object.id === id) {
return {
...item,
object: {
...item.object,
liked: true
}
};
}
return item;
});
});
}
// This sets the context for the onError handler
return {previousInbox};
},
onError: (_err, _id, context) => {
if (context?.previousInbox) {
queryClient.setQueryData([`inbox:${handle}`], context?.previousInbox);
}
},
onSettled: () => {
queryClient.invalidateQueries({queryKey: [`liked:${handle}`]});
}
});
}
export function useUnlikeMutationForUser(handle: string) {
const queryClient = useQueryClient();
const siteUrl = useSiteUrl();
const api = createActivityPubAPI(handle, siteUrl);
return useMutation({
mutationFn(id: string) {
mutationFn: (id: string) => {
return api.unlike(id);
},
onMutate: async (id) => {
const previousInbox = queryClient.getQueryData([`inbox:${handle}`]);
const previousLiked = queryClient.getQueryData([`liked:${handle}`]);
if (previousInbox) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryClient.setQueryData([`inbox:${handle}`], (old?: any[]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return old?.map((item: any) => {
if (item.object.id === id) {
return {
...item,
object: {
...item.object,
liked: false
}
};
}
return item;
});
});
}
if (previousLiked) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
queryClient.setQueryData([`liked:${handle}`], (old?: any[]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return old?.filter((item: any) => item.object.id !== id);
});
}
// This sets the context for the onError handler
return {previousInbox, previousLiked};
},
onError: (_err, _id, context) => {
if (context?.previousInbox) {
queryClient.setQueryData([`inbox:${handle}`], context?.previousInbox);
}
if (context?.previousLiked) {
queryClient.setQueryData([`liked:${handle}`], context?.previousLiked);
}
}
});
}