mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-30 22:34:01 -05:00
WIP
ref https://linear.app/ghost/issue/AP-540/clicking-comment-icon-on-posts-and-likes-tabs-of-your-profile-doesnt
This commit is contained in:
parent
bf714ac22f
commit
3cbc28bdbb
4 changed files with 94 additions and 48 deletions
|
@ -1,24 +1,23 @@
|
|||
import APAvatar from './global/APAvatar';
|
||||
import ActivityItem, {type Activity} from './activities/ActivityItem';
|
||||
import ActivityItem from './activities/ActivityItem';
|
||||
import ActivityPubWelcomeImage from '../assets/images/ap-welcome.png';
|
||||
import ArticleModal from './feed/ArticleModal';
|
||||
import FeedItem from './feed/FeedItem';
|
||||
import MainNavigation from './navigation/MainNavigation';
|
||||
import NiceModal from '@ebay/nice-modal-react';
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
import React, {useEffect, useRef} from 'react';
|
||||
import ViewProfileModal from './global/ViewProfileModal';
|
||||
import getUsername from '../utils/get-username';
|
||||
import {ActorProperties, ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
||||
import {Button, Heading, LoadingIndicator} from '@tryghost/admin-x-design-system';
|
||||
import {getContentAuthor} from '../utils/content-helpers';
|
||||
import {useActivitiesForUser, useSuggestedProfiles} from '../hooks/useActivityPubQueries';
|
||||
import {useArticleModal} from '../hooks/useArticleModal';
|
||||
import {useLayout} from '../hooks/layout';
|
||||
import {useRouting} from '@tryghost/admin-x-framework/routing';
|
||||
|
||||
interface InboxProps {}
|
||||
|
||||
const Inbox: React.FC<InboxProps> = ({}) => {
|
||||
const [, setArticleContent] = useState<ObjectProperties | null>(null);
|
||||
const [, setArticleActor] = useState<ActorProperties | null>(null);
|
||||
const {handleViewContent} = useArticleModal();
|
||||
const {layout} = useLayout();
|
||||
|
||||
const {
|
||||
|
@ -45,36 +44,6 @@ const Inbox: React.FC<InboxProps> = ({}) => {
|
|||
return !activity.object.inReplyTo;
|
||||
});
|
||||
|
||||
const handleViewContent = (object: ObjectProperties, actor: ActorProperties, comments: Activity[], focusReply = false) => {
|
||||
setArticleContent(object);
|
||||
setArticleActor(actor);
|
||||
NiceModal.show(ArticleModal, {object, actor, comments, focusReply});
|
||||
};
|
||||
|
||||
function getContentAuthor(activity: Activity) {
|
||||
const actor = activity.actor;
|
||||
const attributedTo = activity.object.attributedTo;
|
||||
|
||||
if (!attributedTo) {
|
||||
return actor;
|
||||
}
|
||||
|
||||
if (typeof attributedTo === 'string') {
|
||||
return actor;
|
||||
}
|
||||
|
||||
if (Array.isArray(attributedTo)) {
|
||||
const found = attributedTo.find(item => typeof item !== 'string');
|
||||
if (found) {
|
||||
return found;
|
||||
} else {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
return attributedTo;
|
||||
}
|
||||
|
||||
// Intersection observer to fetch more activities when the user scrolls
|
||||
// to the bottom of the page
|
||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||
|
@ -123,7 +92,8 @@ const Inbox: React.FC<InboxProps> = ({}) => {
|
|||
onClick={() => handleViewContent(
|
||||
activity.object,
|
||||
getContentAuthor(activity),
|
||||
activity.object.replies
|
||||
activity.object.replies,
|
||||
false
|
||||
)}
|
||||
>
|
||||
<FeedItem
|
||||
|
|
|
@ -7,9 +7,9 @@ import React, {useEffect, useRef, useState} from 'react';
|
|||
import getUsername from '../utils/get-username';
|
||||
import {ActorProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
||||
|
||||
import ArticleModal from './feed/ArticleModal';
|
||||
import ViewProfileModal from './global/ViewProfileModal';
|
||||
import {Button, Heading, List, NoValueLabel, Tab, TabView} from '@tryghost/admin-x-design-system';
|
||||
import {useArticleModal} from '../hooks/useArticleModal';
|
||||
import {
|
||||
useFollowersCountForUser,
|
||||
useFollowersExpandedForUser,
|
||||
|
@ -73,12 +73,36 @@ const Profile: React.FC<ProfileProps> = ({}) => {
|
|||
});
|
||||
};
|
||||
|
||||
const handlePostClick = (activity: Activity) => {
|
||||
NiceModal.show(ArticleModal, {
|
||||
object: activity.object,
|
||||
actor: activity.actor,
|
||||
comments: activity.object.replies || []
|
||||
});
|
||||
const {handleViewContent} = useArticleModal();
|
||||
|
||||
const handlePostClick = (activity: Activity, focusReply: boolean) => {
|
||||
const object = activity.object;
|
||||
let author: ActorProperties;
|
||||
|
||||
// Handle different possible formats of attributedTo
|
||||
if (object?.attributedTo) {
|
||||
if (Array.isArray(object.attributedTo)) {
|
||||
// If it's an array, find the first non-string item
|
||||
const foundAuthor = object.attributedTo.find(item => typeof item !== 'string');
|
||||
author = foundAuthor as ActorProperties || activity.actor;
|
||||
} else if (typeof object.attributedTo === 'string') {
|
||||
// If it's a string, use the activity actor
|
||||
author = activity.actor;
|
||||
} else {
|
||||
// If it's an object, use it directly
|
||||
author = object.attributedTo as ActorProperties;
|
||||
}
|
||||
} else {
|
||||
// Fallback to activity actor if no attributedTo
|
||||
author = activity.actor;
|
||||
}
|
||||
|
||||
handleViewContent(
|
||||
object,
|
||||
author,
|
||||
object.replies || [],
|
||||
focusReply
|
||||
);
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
|
@ -97,14 +121,14 @@ const Profile: React.FC<ProfileProps> = ({}) => {
|
|||
<li
|
||||
key={activity.id}
|
||||
data-test-view-article
|
||||
onClick={() => handlePostClick(activity)}
|
||||
onClick={() => handlePostClick(activity, false)}
|
||||
>
|
||||
<FeedItem
|
||||
actor={activity.object?.attributedTo || activity.actor}
|
||||
layout={layout}
|
||||
object={activity.object}
|
||||
type={activity.type}
|
||||
onCommentClick={() => {}}
|
||||
onCommentClick={() => handlePostClick(activity, true)}
|
||||
/>
|
||||
{index < posts.length - 1 && (
|
||||
<div className="h-px w-full bg-grey-200"></div>
|
||||
|
@ -142,14 +166,14 @@ const Profile: React.FC<ProfileProps> = ({}) => {
|
|||
<li
|
||||
key={activity.id}
|
||||
data-test-view-article
|
||||
onClick={() => handlePostClick(activity)}
|
||||
onClick={() => handlePostClick(activity, false)}
|
||||
>
|
||||
<FeedItem
|
||||
actor={activity.object?.attributedTo || activity.actor}
|
||||
layout={layout}
|
||||
object={Object.assign({}, activity.object, {liked: true})}
|
||||
type={activity.type}
|
||||
onCommentClick={() => {}}
|
||||
onCommentClick={() => handlePostClick(activity, true)}
|
||||
/>
|
||||
{index < liked.length - 1 && (
|
||||
<div className="h-px w-full bg-grey-200"></div>
|
||||
|
|
27
apps/admin-x-activitypub/src/hooks/useArticleModal.ts
Normal file
27
apps/admin-x-activitypub/src/hooks/useArticleModal.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import ArticleModal from '../components/feed/ArticleModal';
|
||||
import NiceModal from '@ebay/nice-modal-react';
|
||||
import {type Activity} from '../components/activities/ActivityItem';
|
||||
import {ActorProperties, ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
|
||||
import {useState} from 'react';
|
||||
|
||||
export function useArticleModal() {
|
||||
const [articleContent, setArticleContent] = useState<ObjectProperties | null>(null);
|
||||
const [articleActor, setArticleActor] = useState<ActorProperties | null>(null);
|
||||
|
||||
const handleViewContent = (
|
||||
object: ObjectProperties,
|
||||
contentActor: ActorProperties,
|
||||
comments: Activity[],
|
||||
focusReply = false
|
||||
) => {
|
||||
setArticleContent(object);
|
||||
setArticleActor(contentActor);
|
||||
NiceModal.show(ArticleModal, {object, actor: contentActor, comments, focusReply});
|
||||
};
|
||||
|
||||
return {
|
||||
articleContent,
|
||||
articleActor,
|
||||
handleViewContent
|
||||
};
|
||||
}
|
25
apps/admin-x-activitypub/src/utils/content-helpers.ts
Normal file
25
apps/admin-x-activitypub/src/utils/content-helpers.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import {type Activity} from '../components/activities/ActivityItem';
|
||||
|
||||
export function getContentAuthor(activity: Activity) {
|
||||
const actor = activity.actor;
|
||||
const attributedTo = activity.object.attributedTo;
|
||||
|
||||
if (!attributedTo) {
|
||||
return actor;
|
||||
}
|
||||
|
||||
if (typeof attributedTo === 'string') {
|
||||
return actor;
|
||||
}
|
||||
|
||||
if (Array.isArray(attributedTo)) {
|
||||
const found = attributedTo.find(item => typeof item !== 'string');
|
||||
if (found) {
|
||||
return found;
|
||||
} else {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
return attributedTo;
|
||||
}
|
Loading…
Reference in a new issue