From 7537cbaa6dd117535cd736441eea606f3432fdfd Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Sat, 3 Feb 2024 15:26:13 +0100 Subject: [PATCH] feat(inbox): add functionality to 'context' button, highlighting reply in single comment thread --- src/app.tsx | 1 + .../post/comment-tools/comment-tools.tsx | 14 ++++--- src/components/reply/reply.module.css | 9 ++++- src/components/reply/reply.tsx | 26 +++++++++---- src/lib/utils/cid-utils.ts | 39 +++++++++++++++++++ src/lib/utils/view-utils.ts | 4 ++ src/views/post/post.tsx | 17 ++++++-- 7 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 src/lib/utils/cid-utils.ts diff --git a/src/app.tsx b/src/app.tsx index d1335904..292f73b5 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -86,6 +86,7 @@ function App() { } /> } /> + } /> } /> } /> diff --git a/src/components/post/comment-tools/comment-tools.tsx b/src/components/post/comment-tools/comment-tools.tsx index 95b9a8c7..ebf7bd11 100644 --- a/src/components/post/comment-tools/comment-tools.tsx +++ b/src/components/post/comment-tools/comment-tools.tsx @@ -21,6 +21,7 @@ interface CommentToolsProps { isReply?: boolean; isSingleReply?: boolean; parentCid?: string; + postCid?: string; removed?: boolean; replyCount?: number; spoiler?: boolean; @@ -86,9 +87,11 @@ const ReplyTools = ({ author, cid, hasLabel, index, isAuthor, isMod, showReplyFo ); }; -const SingleReplyTools = ({ author, cid, hasLabel, index, isAuthor, isMod, parentCid, showReplyForm, subplebbitAddress }: CommentToolsProps) => { +const SingleReplyTools = ({ author, cid, hasLabel, index, isAuthor, isMod, parentCid, postCid, showReplyForm, subplebbitAddress }: CommentToolsProps) => { const { t } = useTranslation(); - const comment = useComment({ commentCid: parentCid }); + const comment = useComment({ commentCid: postCid }); + + const hasContext = parentCid !== postCid; return ( <> @@ -100,10 +103,10 @@ const SingleReplyTools = ({ author, cid, hasLabel, index, isAuthor, isMod, paren {isAuthor && }
  • - {t('context')} + {t('context')}
  • - + {t('full_comments')} ({comment?.replyCount || 0})
  • @@ -147,6 +150,7 @@ const CommentTools = ({ isReply, isSingleReply, parentCid, + postCid, removed, replyCount, spoiler, @@ -172,6 +176,7 @@ const CommentTools = ({ isAuthor={isAuthor} isMod={isMod} parentCid={parentCid} + postCid={postCid} showReplyForm={showReplyForm} subplebbitAddress={subplebbitAddress} /> @@ -183,7 +188,6 @@ const CommentTools = ({ index={index} isAuthor={isAuthor} isMod={isMod} - parentCid={parentCid} showReplyForm={showReplyForm} subplebbitAddress={subplebbitAddress} /> diff --git a/src/components/reply/reply.module.css b/src/components/reply/reply.module.css index 5bf6e429..37ccd54a 100644 --- a/src/components/reply/reply.module.css +++ b/src/components/reply/reply.module.css @@ -106,6 +106,13 @@ margin-top: 5px; } +.highlightMedia { + background-color: var(--yellow-highlight); + padding: 2px 5px; + display: inline-block; + width: 100%; +} + .md { margin-top: 5px; margin-bottom: 5px; @@ -121,7 +128,7 @@ color: var(--markdown-link) !important; } -.singleCommentHighlight { +.highlightContent { background-color: var(--yellow-highlight); padding: 2px 5px; } diff --git a/src/components/reply/reply.tsx b/src/components/reply/reply.tsx index c45a7c1c..be3f19d3 100644 --- a/src/components/reply/reply.tsx +++ b/src/components/reply/reply.tsx @@ -1,7 +1,7 @@ import { Fragment, useEffect, useMemo, useState } from 'react'; import { Comment, useAccountComment, useAuthorAddress, useBlock, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'; -import { Link, useLocation } from 'react-router-dom'; +import { Link, useLocation, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import styles from './reply.module.css'; import useReplies from '../../hooks/use-replies'; @@ -18,7 +18,7 @@ import ReplyForm from '../reply-form'; import useDownvote from '../../hooks/use-downvote'; import useStateString from '../../hooks/use-state-string'; import useUpvote from '../../hooks/use-upvote'; -import { isInboxView } from '../../lib/utils/view-utils'; +import { isInboxView, isPostContextView } from '../../lib/utils/view-utils'; import { getShortAddress } from '@plebbit/plebbit-js'; import Markdown from '../markdown'; @@ -183,6 +183,7 @@ const InboxParentInfo = ({ address, cid, markedAsRead, shortAddress, subplebbitA }; interface ReplyProps { + cidOfReplyWithContext?: string; depth?: number; index?: number; isNotification?: boolean; @@ -191,7 +192,7 @@ interface ReplyProps { reply: Comment | undefined; } -const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = false, reply = {} }: ReplyProps) => { +const Reply = ({ cidOfReplyWithContext, depth = 0, isSingleComment, isSingleReply, isNotification = false, reply = {} }: ReplyProps) => { // handle pending mod or author edit const { editedComment: editedPost } = useEditedComment({ comment: reply }); if (editedPost) { @@ -209,6 +210,7 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal linkWidth, markedAsRead, pinned, + parentCid, postCid, removed, spoiler, @@ -271,7 +273,9 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal const parentOfPendingReply = useComment({ commentCid: pendingReply?.parentCid }); const location = useLocation(); + const params = useParams(); const isInInboxView = isInboxView(location.pathname); + const isInPostContextView = isPostContextView(location.pathname, params); return (
    @@ -291,7 +295,7 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal [{collapsed ? '+' : '–'}] - + {scoreString} {getFormattedTimeAgo(timestamp)}{' '} {pinned && - {t('stickied_comment')}} {collapsed && ({childrenString})} @@ -316,7 +320,7 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal /> )} {!collapsed && ( -
    +
    {commentMediaInfo && ( )} -
    +
    @@ -344,7 +348,8 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal isReply={true} isSingleReply={isSingleReply} index={reply?.index} - parentCid={postCid} + parentCid={parentCid} + postCid={postCid} removed={removed} replyCount={replies.length} spoiler={spoiler} @@ -357,7 +362,12 @@ const Reply = ({ depth = 0, isSingleComment, isSingleReply, isNotification = fal return ( {!depth || depth < 9 ? ( - + ) : (
    continue this thread diff --git a/src/lib/utils/cid-utils.ts b/src/lib/utils/cid-utils.ts new file mode 100644 index 00000000..3258c001 --- /dev/null +++ b/src/lib/utils/cid-utils.ts @@ -0,0 +1,39 @@ +import { Comment } from '@plebbit/plebbit-react-hooks'; + +export const findTopParentCidOfReply = (replyCid: string, post: Comment): string | null => { + if (!post.replyCount || post.replyCount === 0) { + return null; + } + + for (const firstLevelReply of post.replies?.pages?.topAll?.comments) { + if (firstLevelReply.cid === replyCid) { + return firstLevelReply.cid; + } + + const result = findInDeeperReplies(replyCid, firstLevelReply, firstLevelReply.cid); + if (result) { + return result; + } + } + + return null; +}; + +const findInDeeperReplies = (replyCid: string, currentReply: Comment, firstLevelParentCid: string): string | null => { + if (currentReply.replyCount > 0 && currentReply.replies?.pages?.topAll?.comments) { + for (const deeperReply of currentReply.replies.pages.topAll.comments) { + if (deeperReply.cid === replyCid) { + return firstLevelParentCid; + } + + const result = findInDeeperReplies(replyCid, deeperReply, firstLevelParentCid); + if (result) { + return result; + } + } + } + + return null; +}; + +export default findTopParentCidOfReply; diff --git a/src/lib/utils/view-utils.ts b/src/lib/utils/view-utils.ts index 56809729..0c76df15 100644 --- a/src/lib/utils/view-utils.ts +++ b/src/lib/utils/view-utils.ts @@ -88,6 +88,10 @@ export const isPostView = (pathname: string, params: ParamsType): boolean => { return params.subplebbitAddress && params.commentCid ? pathname.startsWith(`/p/${params.subplebbitAddress}/c/${params.commentCid}`) : false; }; +export const isPostContextView = (pathname: string, params: ParamsType): boolean => { + return params.subplebbitAddress && params.commentCid ? pathname.startsWith(`/p/${params.subplebbitAddress}/c/${params.commentCid}/context`) : false; +}; + export const isProfileView = (pathname: string): boolean => { return pathname.startsWith(`/profile`); }; diff --git a/src/views/post/post.tsx b/src/views/post/post.tsx index 5cd2b5e9..9e3c89b3 100644 --- a/src/views/post/post.tsx +++ b/src/views/post/post.tsx @@ -10,25 +10,33 @@ import PostComponent from '../../components/post'; import Sidebar from '../../components/sidebar/'; import useReplies from '../../hooks/use-replies'; import useStateString from '../../hooks/use-state-string'; -import { isPendingView } from '../../lib/utils/view-utils'; +import { isPendingView, isPostContextView } from '../../lib/utils/view-utils'; +import findTopParentCidOfReply from '../../lib/utils/cid-utils'; const Post = () => { const { t } = useTranslation(); const params = useParams(); const location = useLocation(); const isInPendingView = isPendingView(location.pathname, params); + const isInPostContextView = isPostContextView(location.pathname, params); const comment = useComment({ commentCid: params?.commentCid }); const pendingPost = useAccountComment({ commentIndex: params?.accountCommentIndex as any }); + + // if in inbox reply context view, get the context comment + const postComment = useComment({ commentCid: comment?.postCid }); + const topParentCid = findTopParentCidOfReply(comment.cid, postComment); + const topParentComment = useComment({ commentCid: topParentCid || '' }); + const post = isInPendingView ? pendingPost : comment; const isSingleComment = comment?.parentCid ? true : false; // in pending page, redirect to post view when post.cid is received const navigate = useNavigate(); useEffect(() => { - if (post?.cid && post?.subplebbitAddress) { + if (post?.cid && post?.subplebbitAddress && !isInPostContextView) { navigate(`/p/${post?.subplebbitAddress}/c/${post?.cid}`, { replace: true }); } - }, [post?.cid, post?.subplebbitAddress, navigate]); + }, [post?.cid, post?.subplebbitAddress, navigate, isInPostContextView]); const { cid, downvoteCount, postCid, replyCount, subplebbitAddress, timestamp, title, upvoteCount } = comment || {}; const subplebbit = useSubplebbit({ subplebbitAddress }); @@ -99,7 +107,8 @@ const Post = () => {
    )}
    - {isSingleComment && } + {isSingleComment && isInPostContextView && } + {isSingleComment && !isInPostContextView && } {!isSingleComment && replies.map((reply, index) => )}