mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Wired Repost button to the new ActivityPub endpoint (#22111)
ref https://linear.app/ghost/issue/AP-699 - wired the frontend to the new Create Repost API endpoint (POST /actions/repost/:id) - the UX/UI is yet to be worked on by Djordje - the frontend activity-pub app is currently missing acceptance tests altogether. A follow-up commit will set up and add a basic acceptance test to the FE app, so that we can add tests as we ship new changes
This commit is contained in:
parent
6c4c94c5a8
commit
d0df0e7f45
3 changed files with 67 additions and 1 deletions
|
@ -219,6 +219,11 @@ export class ActivityPubAPI {
|
||||||
await this.fetchJSON(url, 'POST');
|
await this.fetchJSON(url, 'POST');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async repost(id: string): Promise<void> {
|
||||||
|
const url = new URL(`.ghost/activitypub/actions/repost/${encodeURIComponent(id)}`, this.apiUrl);
|
||||||
|
await this.fetchJSON(url, 'POST');
|
||||||
|
}
|
||||||
|
|
||||||
get activitiesApiUrl() {
|
get activitiesApiUrl() {
|
||||||
return new URL(`.ghost/activitypub/activities/${this.handle}`, this.apiUrl);
|
return new URL(`.ghost/activitypub/activities/${this.handle}`, this.apiUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Button} from '@tryghost/admin-x-design-system';
|
import {Button} from '@tryghost/admin-x-design-system';
|
||||||
import {ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
import {ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
||||||
import {useLikeMutationForUser, useUnlikeMutationForUser} from '../../hooks/useActivityPubQueries';
|
import {useLikeMutationForUser, useRepostMutationForUser, useUnlikeMutationForUser} from '../../hooks/useActivityPubQueries';
|
||||||
|
|
||||||
interface FeedItemStatsProps {
|
interface FeedItemStatsProps {
|
||||||
object: ObjectProperties;
|
object: ObjectProperties;
|
||||||
|
@ -21,8 +21,10 @@ const FeedItemStats: React.FC<FeedItemStatsProps> = ({
|
||||||
onCommentClick
|
onCommentClick
|
||||||
}) => {
|
}) => {
|
||||||
const [isLiked, setIsLiked] = useState(object.liked);
|
const [isLiked, setIsLiked] = useState(object.liked);
|
||||||
|
const [isReposted, setIsReposted] = useState(object.reposted);
|
||||||
const likeMutation = useLikeMutationForUser('index');
|
const likeMutation = useLikeMutationForUser('index');
|
||||||
const unlikeMutation = useUnlikeMutationForUser('index');
|
const unlikeMutation = useUnlikeMutationForUser('index');
|
||||||
|
const repostMutation = useRepostMutationForUser('index');
|
||||||
|
|
||||||
const handleLikeClick = async (e: React.MouseEvent<HTMLElement>) => {
|
const handleLikeClick = async (e: React.MouseEvent<HTMLElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -68,6 +70,22 @@ const FeedItemStats: React.FC<FeedItemStatsProps> = ({
|
||||||
onCommentClick();
|
onCommentClick();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
className={buttonClassName}
|
||||||
|
icon='reload'
|
||||||
|
iconColorClass={`w-[18px] h-[18px] ${isReposted && 'text-green'}`}
|
||||||
|
id='repost'
|
||||||
|
size='md'
|
||||||
|
unstyled={true}
|
||||||
|
onClick={(e?: React.MouseEvent<HTMLElement>) => {
|
||||||
|
e?.stopPropagation();
|
||||||
|
|
||||||
|
if (!isReposted) {
|
||||||
|
repostMutation.mutate(object.id);
|
||||||
|
setIsReposted(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>);
|
</div>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,49 @@ export function useUnlikeMutationForUser(handle: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useRepostMutationForUser(handle: string) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
async mutationFn(id: string) {
|
||||||
|
const siteUrl = await getSiteUrl();
|
||||||
|
const api = createActivityPubAPI(handle, siteUrl);
|
||||||
|
return api.repost(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,
|
||||||
|
reposted: 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: [`reposted:${handle}`]});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function useUserDataForUser(handle: string) {
|
export function useUserDataForUser(handle: string) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [`user:${handle}`],
|
queryKey: [`user:${handle}`],
|
||||||
|
|
Loading…
Add table
Reference in a new issue