From 12710eaefae7e1ae8e0cf4b726c97d60d86f3816 Mon Sep 17 00:00:00 2001 From: Michael Barrett Date: Mon, 16 Sep 2024 16:49:52 +0100 Subject: [PATCH] Added open reply notification in sidebar functionality (#21014) no refs Added logic to open the notification in the sidebar when the notification is clicked if it is a reply notification --- .../src/components/Activities.tsx | 67 +++++++++++-------- .../components/activities/ActivityItem.tsx | 16 ++++- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/apps/admin-x-activitypub/src/components/Activities.tsx b/apps/admin-x-activitypub/src/components/Activities.tsx index 9e3b29accb..11b5724ffd 100644 --- a/apps/admin-x-activitypub/src/components/Activities.tsx +++ b/apps/admin-x-activitypub/src/components/Activities.tsx @@ -1,9 +1,12 @@ +import NiceModal from '@ebay/nice-modal-react'; import React from 'react'; +import {Button, NoValueLabel} from '@tryghost/admin-x-design-system'; +import {ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub'; import APAvatar, {AvatarBadge} from './global/APAvatar'; -import ActivityItem from './activities/ActivityItem'; +import ActivityItem, {type Activity} from './activities/ActivityItem'; +import ArticleModal from './feed/ArticleModal'; import MainNavigation from './navigation/MainNavigation'; -import {Button, NoValueLabel} from '@tryghost/admin-x-design-system'; import getUsername from '../utils/get-username'; import {useBrowseInboxForUser, useBrowseOutboxForUser, useFollowersForUser} from '../MainContent'; @@ -18,28 +21,7 @@ enum ACTVITY_TYPE { FOLLOW = 'Follow' } -type Actor = { - id: string - name: string - preferredUsername: string - url: string -} - -type ActivityObject = { - name: string - url: string - inReplyTo: string | null - content: string -} - -type Activity = { - id: string - type: ACTVITY_TYPE - object?: ActivityObject - actor: Actor -} - -const getActivityDescription = (activity: Activity, activityObjectsMap: Map): string => { +const getActivityDescription = (activity: Activity, activityObjectsMap: Map): string => { switch (activity.type) { case ACTVITY_TYPE.CREATE: const object = activityObjectsMap.get(activity.object?.inReplyTo || ''); @@ -76,7 +58,7 @@ const getExtendedDescription = (activity: Activity): JSX.Element | null => { const getActivityUrl = (activity: Activity): string | null => { if (activity.object) { - return activity.object.url; + return activity.object.url || null; } return null; @@ -119,7 +101,7 @@ const Activities: React.FC = ({}) => { // This allows us to quickly look up an object associated with an activity // We could just make a http request to get the object, but this is more // efficient seeming though we already have the data in the inbox and outbox - const activityObjectsMap = new Map(); + const activityObjectsMap = new Map(); outboxActivities.forEach((activity) => { if (activity.object) { @@ -161,6 +143,24 @@ const Activities: React.FC = ({}) => { // to show the most recent activities first .reverse(); + // Create a map of activity comments, grouping them by the parent activity + // This allows us to quickly look up all comments for a given activity + const commentsMap = new Map(); + + for (const activity of activities) { + if (activity.type === ACTVITY_TYPE.CREATE && activity.object?.inReplyTo) { + const comments = commentsMap.get(activity.object.inReplyTo) ?? []; + + comments.push(activity); + + commentsMap.set(activity.object.inReplyTo, comments.reverse()); + } + } + + const getCommentsForObject = (id: string) => { + return commentsMap.get(id) ?? []; + }; + // Retrieve followers for the user const {data: followers = []} = useFollowersForUser(user); @@ -182,7 +182,20 @@ const Activities: React.FC = ({}) => { {activities.length > 0 && (
{activities?.map(activity => ( - + { + NiceModal.show(ArticleModal, { + object: activity.object, + actor: activity.actor, + comments: getCommentsForObject(activity.object.id), + allComments: commentsMap + }); + } : undefined + } + >
diff --git a/apps/admin-x-activitypub/src/components/activities/ActivityItem.tsx b/apps/admin-x-activitypub/src/components/activities/ActivityItem.tsx index 3156902c7b..e48e04323a 100644 --- a/apps/admin-x-activitypub/src/components/activities/ActivityItem.tsx +++ b/apps/admin-x-activitypub/src/components/activities/ActivityItem.tsx @@ -13,13 +13,18 @@ export type Activity = { interface ActivityItemProps { children?: ReactNode; url?: string | null; + onClick?: () => void; } -const ActivityItem: React.FC = ({children, url = null}) => { +const ActivityItem: React.FC = ({children, url = null, onClick}) => { const childrenArray = React.Children.toArray(children); const Item = ( -
+
{ + if (!url && onClick) { + onClick(); + } + }}>
{childrenArray[0]} {childrenArray[1]} @@ -30,7 +35,12 @@ const ActivityItem: React.FC = ({children, url = null}) => { if (url) { return ( - + { + if (onClick) { + e.preventDefault(); + onClick(); + } + }}> {Item} );