From 6a858a4eeccdba70c051b67a9077b69d83482ab5 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 25 Mar 2024 16:20:18 +0700 Subject: [PATCH 1/3] fix draft message sync issue --- .../ComposerWithSuggestions.tsx | 7 +++++++ .../SilentCommentUpdater/index.tsx | 4 ++-- .../ReportActionCompose/SilentCommentUpdater/types.ts | 3 +++ src/pages/home/report/ReportActionItemMessageEdit.tsx | 11 ++++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index cf3761a8d76a..3d24412ebeb5 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -288,6 +288,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. @@ -323,6 +326,7 @@ function ComposerWithSuggestions( () => lodashDebounce((selectedReportID, newComment) => { Report.saveReportComment(selectedReportID, newComment || ''); + isCommentPendingSaved.current = false; }, 1000), [], ); @@ -433,6 +437,7 @@ function ComposerWithSuggestions( commentRef.current = newCommentConverted; if (shouldDebounceSaveComment) { + isCommentPendingSaved.current = true; debouncedSaveReportComment(reportID, newCommentConverted); } else { Report.saveReportComment(reportID, newCommentConverted || ''); @@ -481,6 +486,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); @@ -782,6 +788,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..4cfa7da96c29 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). diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts index dbc23b0279c3..85de03c88228 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 b5c18976aa86..fcf281a61048 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -124,9 +124,15 @@ function ReportActionItemMessageEdit( const isFocusedRef = useRef(false); const insertedEmojis = useRef([]); const draftRef = useRef(draft); + // The ref to check whether the comment saving is in progress + const isCommentPendingSaved = useRef(false); useEffect(() => { - if (ReportActionsUtils.isDeletedAction(action) || Boolean(action.message && draftMessage === action.message[0].html) || Boolean(prevDraftMessage === draftMessage)) { + if ( + ReportActionsUtils.isDeletedAction(action) || + Boolean(action.message && draftMessage === action.message[0].html) || + Boolean(prevDraftMessage === draftMessage || isCommentPendingSaved.current) + ) { return; } setDraft(Str.htmlDecode(draftMessage)); @@ -227,6 +233,7 @@ function ReportActionItemMessageEdit( () => lodashDebounce((newDraft: string) => { Report.saveReportActionDraft(reportID, action, newDraft); + isCommentPendingSaved.current = false; }, 1000), [reportID, action], ); @@ -276,6 +283,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], ); @@ -290,6 +298,7 @@ function ReportActionItemMessageEdit( */ const deleteDraft = useCallback(() => { debouncedSaveDraft.cancel(); + isCommentPendingSaved.current = false; Report.deleteReportActionDraft(reportID, action); if (isActive()) { From 40505c4a885c8e976cfd976fd4ee7db1b1bee212 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 25 Mar 2024 16:34:43 +0700 Subject: [PATCH 2/3] fix lint --- .../report/ReportActionCompose/SilentCommentUpdater/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx index 4cfa7da96c29..c95e6bde67ee 100644 --- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx +++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/index.tsx @@ -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; } From 333d3ff27b6bb116b804cca3c5de4d1895698ea0 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 25 Mar 2024 16:44:39 +0700 Subject: [PATCH 3/3] fix lint --- .../report/ReportActionCompose/SilentCommentUpdater/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts index 85de03c88228..6f9e8b8a6d42 100644 --- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts +++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater/types.ts @@ -19,7 +19,7 @@ type SilentCommentUpdaterProps = SilentCommentUpdaterOnyxProps & { commentRef: React.RefObject; /** The ref to check whether the comment saving is in progress */ - isCommentPendingSaved: React.RefObject + isCommentPendingSaved: React.RefObject; }; export type {SilentCommentUpdaterProps, SilentCommentUpdaterOnyxProps};