diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index 734a94d50d38..ab3ed32f5ee8 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -296,6 +296,9 @@ function ComposerWithSuggestions( const isAutoSuggestionPickerLarge = !isSmallScreenWidth || (isSmallScreenWidth && hasEnoughSpaceForLargeSuggestion); + // The ref to check whether the comment saving is in progress + const isCommentPendingSaved = useRef(false); + /** * Update frequently used emojis list. We debounce this method in the constructor so that UpdateFrequentlyUsedEmojis * API is not called too often. @@ -331,6 +334,7 @@ function ComposerWithSuggestions( () => lodashDebounce((selectedReportID, newComment) => { Report.saveReportComment(selectedReportID, newComment || ''); + isCommentPendingSaved.current = false; }, 1000), [], ); @@ -441,6 +445,7 @@ function ComposerWithSuggestions( commentRef.current = newCommentConverted; if (shouldDebounceSaveComment) { + isCommentPendingSaved.current = true; debouncedSaveReportComment(reportID, newCommentConverted); } else { Report.saveReportComment(reportID, newCommentConverted || ''); @@ -489,6 +494,7 @@ function ComposerWithSuggestions( // We don't really care about saving the draft the user was typing // We need to make sure an empty draft gets saved instead debouncedSaveReportComment.cancel(); + isCommentPendingSaved.current = false; updateComment(''); setTextInputShouldClear(true); @@ -794,6 +800,7 @@ function ComposerWithSuggestions( value={value} updateComment={updateComment} commentRef={commentRef} + isCommentPendingSaved={isCommentPendingSaved} /> )} diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx index f3780528cabe..c95e6bde67ee 100644 --- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx +++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx @@ -10,7 +10,7 @@ import type {SilentCommentUpdaterOnyxProps, SilentCommentUpdaterProps} from './t * It is connected to the actual draft comment in onyx. The comment in onyx might updates multiple times, and we want to avoid * re-rendering a UI component for that. That's why the side effect was moved down to a separate component. */ -function SilentCommentUpdater({comment, commentRef, reportID, value, updateComment}: SilentCommentUpdaterProps) { +function SilentCommentUpdater({comment, commentRef, reportID, value, updateComment, isCommentPendingSaved}: SilentCommentUpdaterProps) { const prevCommentProp = usePrevious(comment); const prevReportId = usePrevious(reportID); const {preferredLocale} = useLocalize(); @@ -34,7 +34,7 @@ function SilentCommentUpdater({comment, commentRef, reportID, value, updateComme useEffect(() => { // Value state does not have the same value as comment props when the comment gets changed from another tab. // In this case, we should synchronize the value between tabs. - const shouldSyncComment = prevCommentProp !== comment && value !== comment; + const shouldSyncComment = prevCommentProp !== comment && value !== comment && !isCommentPendingSaved.current; // As the report IDs change, make sure to update the composer comment as we need to make sure // we do not show incorrect data in there (ie. draft of message from other report). @@ -43,7 +43,7 @@ function SilentCommentUpdater({comment, commentRef, reportID, value, updateComme } updateComment(comment ?? ''); - }, [prevCommentProp, prevPreferredLocale, prevReportId, comment, preferredLocale, reportID, updateComment, value, commentRef]); + }, [prevCommentProp, prevPreferredLocale, prevReportId, comment, preferredLocale, reportID, updateComment, value, commentRef, isCommentPendingSaved]); return null; } diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts index dbc23b0279c3..6f9e8b8a6d42 100644 --- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts +++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts @@ -17,6 +17,9 @@ type SilentCommentUpdaterProps = SilentCommentUpdaterOnyxProps & { /** The ref of the comment */ commentRef: React.RefObject; + + /** The ref to check whether the comment saving is in progress */ + isCommentPendingSaved: React.RefObject; }; export type {SilentCommentUpdaterProps, SilentCommentUpdaterOnyxProps}; diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 56dd1f4aa62c..bd5195f2410f 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -113,11 +113,17 @@ function ReportActionItemMessageEdit( const insertedEmojis = useRef([]); const draftRef = useRef(draft); const emojiPickerSelectionRef = useRef(undefined); + // The ref to check whether the comment saving is in progress + const isCommentPendingSaved = useRef(false); useEffect(() => { const parser = new ExpensiMark(); const originalMessage = parser.htmlToMarkdown(action.message?.[0].html ?? ''); - if (ReportActionsUtils.isDeletedAction(action) || Boolean(action.message && draftMessage === originalMessage) || Boolean(prevDraftMessage === draftMessage)) { + if ( + ReportActionsUtils.isDeletedAction(action) || + Boolean(action.message && draftMessage === originalMessage) || + Boolean(prevDraftMessage === draftMessage || isCommentPendingSaved.current) + ) { return; } setDraft(draftMessage); @@ -218,11 +224,18 @@ function ReportActionItemMessageEdit( () => lodashDebounce((newDraft: string) => { Report.saveReportActionDraft(reportID, action, newDraft); + isCommentPendingSaved.current = false; }, 1000), [reportID, action], ); - useEffect(() => () => debouncedSaveDraft.cancel(), [debouncedSaveDraft]); + useEffect( + () => () => { + debouncedSaveDraft.cancel(); + isCommentPendingSaved.current = false; + }, + [debouncedSaveDraft], + ); /** * Update frequently used emojis list. We debounce this method in the constructor so that UpdateFrequentlyUsedEmojis @@ -269,6 +282,7 @@ function ReportActionItemMessageEdit( // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. debouncedSaveDraft(newDraft); + isCommentPendingSaved.current = true; }, [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, preferredSkinTone, preferredLocale, selection.end], );