[WIKI-510] feat: enhance issue description input with unsaved changes tracking (#7357)

This commit is contained in:
M. Palanikannan 2025-07-08 14:58:41 +05:30 committed by GitHub
parent 388588c588
commit 13ab0624d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,6 @@
"use client"; "use client";
import { FC, useCallback, useEffect, useState } from "react"; import { FC, useCallback, useEffect, useRef, useState } from "react";
import debounce from "lodash/debounce"; import debounce from "lodash/debounce";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
@ -53,6 +53,8 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
id: issueId, id: issueId,
description_html: initialValue, description_html: initialValue,
}); });
// ref to track if there are unsaved changes
const hasUnsavedChanges = useRef(false);
// store hooks // store hooks
const { uploadEditorAsset } = useEditorAsset(); const { uploadEditorAsset } = useEditorAsset();
const { getWorkspaceBySlug } = useWorkspace(); const { getWorkspaceBySlug } = useWorkspace();
@ -87,6 +89,8 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
id: issueId, id: issueId,
description_html: initialValue === "" ? "<p></p>" : initialValue, description_html: initialValue === "" ? "<p></p>" : initialValue,
}); });
// Reset unsaved changes flag when form is reset
hasUnsavedChanges.current = false;
}, [initialValue, issueId, reset]); }, [initialValue, issueId, reset]);
// ADDING handleDescriptionFormSubmit TO DEPENDENCY ARRAY PRODUCES ADVERSE EFFECTS // ADDING handleDescriptionFormSubmit TO DEPENDENCY ARRAY PRODUCES ADVERSE EFFECTS
@ -94,11 +98,35 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedFormSave = useCallback( const debouncedFormSave = useCallback(
debounce(async () => { debounce(async () => {
handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted")); handleSubmit(handleDescriptionFormSubmit)().finally(() => {
setIsSubmitting("submitted");
hasUnsavedChanges.current = false;
});
}, 1500), }, 1500),
[handleSubmit, issueId] [handleSubmit, issueId]
); );
// Save on unmount if there are unsaved changes
useEffect(
() => () => {
debouncedFormSave.cancel();
if (hasUnsavedChanges.current) {
handleSubmit(handleDescriptionFormSubmit)()
.catch((error) => {
console.error("Failed to save description on unmount:", error);
})
.finally(() => {
setIsSubmitting("submitted");
hasUnsavedChanges.current = false;
});
}
},
// since we don't want to save on unmount if there are no unsaved changes, no deps are needed
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
if (!workspaceId) return null; if (!workspaceId) return null;
return ( return (
@ -120,6 +148,7 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
onChange={(_description: object, description_html: string) => { onChange={(_description: object, description_html: string) => {
setIsSubmitting("submitting"); setIsSubmitting("submitting");
onChange(description_html); onChange(description_html);
hasUnsavedChanges.current = true;
debouncedFormSave(); debouncedFormSave();
}} }}
placeholder={ placeholder={