From 9e54be51cc948370a8154857600fd6f4e3a4880a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Tue, 17 Mar 2026 14:37:43 -0600 Subject: [PATCH 1/2] Fix suggested followup button: preserve HTML formatting and fix response ordering Bug A: Use dom-serializer render() instead of DomUtils.textContent() to preserve HTML formatting in followup responses. Add isHTML parameter to buildOptimisticAddCommentReportAction to skip getParsedComment() when input is already HTML. Bug B: Add createdOffset: 1 to the Concierge response so its timestamp is 1ms after the question, ensuring correct ordering. The visual typing delay is handled separately by displayAfter in addOptimisticConciergeActionWithDelay. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/libs/ReportActionFollowupUtils/index.ts | 3 ++- src/libs/ReportUtils.ts | 4 +++- src/libs/actions/Report/SuggestedFollowup.ts | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportActionFollowupUtils/index.ts b/src/libs/ReportActionFollowupUtils/index.ts index cc6e9ab99199b..dd591ea2a79cf 100644 --- a/src/libs/ReportActionFollowupUtils/index.ts +++ b/src/libs/ReportActionFollowupUtils/index.ts @@ -1,3 +1,4 @@ +import render from 'dom-serializer'; import {DomUtils, parseDocument} from 'htmlparser2'; import {getReportActionMessage, isActionOfType} from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; @@ -53,7 +54,7 @@ function parseFollowupsFromHtml(html: string): Followup[] | null { const followupTextElement = DomUtils.getElementsByTagName('followup-text', followupEl, true).at(0); const followupResponseElement = DomUtils.getElementsByTagName('followup-response', followupEl, true).at(0); const text = followupTextElement ? DomUtils.textContent(followupTextElement) : ''; - const response = followupResponseElement ? DomUtils.textContent(followupResponseElement) : undefined; + const response = followupResponseElement ? render(followupResponseElement.children) : undefined; return {text, response}; }); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6a63dc83c6e87..d8d1ae5455bc1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -368,6 +368,7 @@ type BuildOptimisticAddCommentReportActionParams = { reportID?: string; reportActionID?: string; attachmentID?: string; + isHTML?: boolean; }; type OptimisticReportAction = { @@ -6399,8 +6400,9 @@ function buildOptimisticAddCommentReportAction({ reportID, reportActionID = rand64(), attachmentID, + isHTML = false, }: BuildOptimisticAddCommentReportActionParams): OptimisticReportAction { - const commentText = getParsedComment(text ?? '', {reportID}); + const commentText = isHTML ? (text ?? '') : getParsedComment(text ?? '', {reportID}); const attachmentHtml = getUploadingAttachmentHtml(file, attachmentID); const htmlForNewComment = `${commentText}${commentText && attachmentHtml ? '

' : ''}${attachmentHtml}`; diff --git a/src/libs/actions/Report/SuggestedFollowup.ts b/src/libs/actions/Report/SuggestedFollowup.ts index 5e55e0f7fa6ee..29b2e3cda2105 100644 --- a/src/libs/actions/Report/SuggestedFollowup.ts +++ b/src/libs/actions/Report/SuggestedFollowup.ts @@ -80,8 +80,10 @@ function resolveSuggestedFollowup( const optimisticConciergeAction = buildOptimisticAddCommentReportAction({ text: selectedFollowup.response, actorAccountID: CONST.ACCOUNT_ID.CONCIERGE, + createdOffset: 1, reportActionID: optimisticConciergeReportActionID, reportID, + isHTML: true, }); addOptimisticConciergeActionWithDelay(reportID, optimisticConciergeAction); From e7435248b6cb3af2caa2a28b21b9374d3fdc0e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Tue, 17 Mar 2026 14:46:49 -0600 Subject: [PATCH 2/2] Strip followup-list from clipboard copy Use stripFollowupListFromHtml in setClipboardMessage so that Q&A content is removed before copying to clipboard. This re-applies the clipboard stripping from PR 84452 which was reverted. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index 69012e109252b..b4ee1c5468a79 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -23,6 +23,7 @@ import Navigation from '@libs/Navigation/Navigation'; import Parser from '@libs/Parser'; import {getCleanedTagName, isPolicyAdmin} from '@libs/PolicyUtils'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; +import stripFollowupListFromHtml from '@libs/ReportActionFollowupUtils/stripFollowupListFromHtml'; import { getActionableCardFraudAlertMessage, getActionableMentionWhisperMessage, @@ -214,14 +215,15 @@ function getActionHtml(reportAction: OnyxInputOrEntry): string { /** Sets the HTML string to Clipboard */ function setClipboardMessage(content: string | undefined) { - if (!content) { + const strippedContent = stripFollowupListFromHtml(content); + if (!strippedContent) { return; } - const clipboardText = getClipboardText(content); + const clipboardText = getClipboardText(strippedContent); if (!Clipboard.canSetHtml()) { Clipboard.setString(clipboardText); } else { - Clipboard.setHtml(content, clipboardText); + Clipboard.setHtml(strippedContent, clipboardText); } }