Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: draft message sync issue #38912

Merged
merged 5 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -331,6 +334,7 @@ function ComposerWithSuggestions(
() =>
lodashDebounce((selectedReportID, newComment) => {
Report.saveReportComment(selectedReportID, newComment || '');
isCommentPendingSaved.current = false;
}, 1000),
[],
);
Expand Down Expand Up @@ -441,6 +445,7 @@ function ComposerWithSuggestions(

commentRef.current = newCommentConverted;
if (shouldDebounceSaveComment) {
isCommentPendingSaved.current = true;
debouncedSaveReportComment(reportID, newCommentConverted);
} else {
Report.saveReportComment(reportID, newCommentConverted || '');
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -794,6 +800,7 @@ function ComposerWithSuggestions(
value={value}
updateComment={updateComment}
commentRef={commentRef}
isCommentPendingSaved={isCommentPendingSaved}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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).
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type SilentCommentUpdaterProps = SilentCommentUpdaterOnyxProps & {

/** The ref of the comment */
commentRef: React.RefObject<string>;

/** The ref to check whether the comment saving is in progress */
isCommentPendingSaved: React.RefObject<boolean>;
};

export type {SilentCommentUpdaterProps, SilentCommentUpdaterOnyxProps};
18 changes: 16 additions & 2 deletions src/pages/home/report/ReportActionItemMessageEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,17 @@ function ReportActionItemMessageEdit(
const insertedEmojis = useRef<Emoji[]>([]);
const draftRef = useRef(draft);
const emojiPickerSelectionRef = useRef<Selection | undefined>(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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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],
);
Expand Down
Loading