From 7e60172027dac51d0f6e3f0ff099fe22be402a74 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 4 Dec 2024 14:38:47 +0000 Subject: [PATCH] Removed link from replied-to ref when deleted/hidden closes https://linear.app/ghost/issue/PLG-294 - making the `replied to: [removed]` text a link was a bit confusing because clicking it does nothing - if the replied-to comment doesn't exist (e.g. hidden/deleted and not returned in API response) or has been unpublished we replace the `` with a `` to remove the link behaviour --- .../src/components/content/Comment.test.jsx | 89 +++++++++++++++---- .../src/components/content/Comment.tsx | 21 ++--- 2 files changed, 85 insertions(+), 25 deletions(-) diff --git a/apps/comments-ui/src/components/content/Comment.test.jsx b/apps/comments-ui/src/components/content/Comment.test.jsx index f93089219c..ed8516263d 100644 --- a/apps/comments-ui/src/components/content/Comment.test.jsx +++ b/apps/comments-ui/src/components/content/Comment.test.jsx @@ -1,5 +1,6 @@ import {AppContext} from '../../AppContext'; -import {CommentComponent} from './Comment'; +import {CommentComponent, RepliedToSnippet} from './Comment'; +import {buildComment} from '../../../test/utils/fixtures'; import {render, screen} from '@testing-library/react'; const contextualRender = (ui, {appContext, ...renderOptions}) => { @@ -20,23 +21,81 @@ const contextualRender = (ui, {appContext, ...renderOptions}) => { describe('', function () { it('renders reply-to-reply content', function () { - const appContext = {labs: {commentImprovements: true}}; - const parent = { - id: '1', - status: 'published', - count: {likes: 0} - }; - const comment = { - id: '3', - status: 'published', - in_reply_to_id: '2', + const reply1 = buildComment({ + html: '

First reply

' + }); + const reply2 = buildComment({ + in_reply_to_id: reply1.id, in_reply_to_snippet: 'First reply', - html: '

Second reply

', - count: {likes: 0} - }; + html: '

Second reply

' + }); + const parent = buildComment({ + replies: [reply1, reply2] + }); + const appContext = {comments: [parent], labs: {commentImprovements: true}}; - contextualRender(, {appContext}); + contextualRender(, {appContext}); expect(screen.getByText('First reply')).toBeInTheDocument(); }); }); + +describe('', function () { + it('renders a link when replied-to comment is published', function () { + const reply1 = buildComment({ + html: '

First reply

' + }); + const reply2 = buildComment({ + in_reply_to_id: reply1.id, + in_reply_to_snippet: 'First reply', + html: '

Second reply

' + }); + const parent = buildComment({ + replies: [reply1, reply2] + }); + const appContext = {comments: [parent], labs: {commentImprovements: true}}; + + contextualRender(, {appContext}); + + const element = screen.getByTestId('comment-in-reply-to'); + expect(element).toBeInstanceOf(HTMLAnchorElement); + }); + + it('does not render a link when replied-to comment is deleted', function () { + const reply1 = buildComment({ + html: '

First reply

', + status: 'deleted' + }); + const reply2 = buildComment({ + in_reply_to_id: reply1.id, + in_reply_to_snippet: 'First reply', + html: '

Second reply

' + }); + const parent = buildComment({ + replies: [reply1, reply2] + }); + const appContext = {comments: [parent], labs: {commentImprovements: true}}; + + contextualRender(, {appContext}); + + const element = screen.getByTestId('comment-in-reply-to'); + expect(element).toBeInstanceOf(HTMLSpanElement); + }); + + it('does not render a link when replied-to comment is missing (i.e. removed)', function () { + const reply2 = buildComment({ + in_reply_to_id: 'missing', + in_reply_to_snippet: 'First reply', + html: '

Second reply

' + }); + const parent = buildComment({ + replies: [reply2] + }); + const appContext = {comments: [parent], labs: {commentImprovements: true}}; + + contextualRender(, {appContext}); + + const element = screen.getByTestId('comment-in-reply-to'); + expect(element).toBeInstanceOf(HTMLSpanElement); + }); +}); diff --git a/apps/comments-ui/src/components/content/Comment.tsx b/apps/comments-ui/src/components/content/Comment.tsx index 7fa50878bf..20b72380a6 100644 --- a/apps/comments-ui/src/components/content/Comment.tsx +++ b/apps/comments-ui/src/components/content/Comment.tsx @@ -279,7 +279,7 @@ const AuthorName: React.FC<{comment: Comment}> = ({comment}) => { ); }; -const RepliedToSnippet: React.FC<{comment: Comment}> = ({comment}) => { +export const RepliedToSnippet: React.FC<{comment: Comment}> = ({comment}) => { const {comments, dispatchAction, t} = useAppContext(); const inReplyToComment = findCommentById(comments, comment.in_reply_to_id); @@ -298,19 +298,20 @@ const RepliedToSnippet: React.FC<{comment: Comment}> = ({comment}) => { }; let inReplyToSnippet = comment.in_reply_to_snippet; - if (inReplyToComment && inReplyToComment.status !== 'published') { + // For public API requests hidden/deleted comments won't exist in the comments array + // unless it was only just deleted in which case it will exist but have a 'deleted' status + if (!inReplyToComment || inReplyToComment.status !== 'published') { inReplyToSnippet = `[${t('removed')}]`; } + const linkToReply = inReplyToComment && inReplyToComment.status === 'published'; + + const className = 'font-semibold text-neutral-900/60 transition-colors hover:text-neutral-900/70 dark:text-white/70 dark:hover:text-white/80'; + return ( -
- {inReplyToSnippet} - + linkToReply + ? {inReplyToSnippet} + : {inReplyToSnippet} ); };