fix: issue details mutation (#389)

This commit is contained in:
Dakshesh Jain 2023-03-07 22:22:06 +05:30 committed by GitHub
parent f725ea5b15
commit 30a91a6b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 27 deletions

View File

@ -1,11 +1,9 @@
import { FC, useCallback, useEffect, useMemo, useState } from "react"; import { FC, useCallback, useEffect, useState } from "react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// lodash
import debounce from "lodash.debounce";
// components // components
import { Loader, TextArea } from "components/ui"; import { Loader, TextArea } from "components/ui";
const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), {
@ -27,7 +25,7 @@ export interface IssueDescriptionFormValues {
export interface IssueDetailsProps { export interface IssueDetailsProps {
issue: IIssue; issue: IIssue;
handleFormSubmit: (value: IssueDescriptionFormValues) => void; handleFormSubmit: (value: IssueDescriptionFormValues) => Promise<void>;
userAuth: UserAuth; userAuth: UserAuth;
} }
@ -36,6 +34,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
handleFormSubmit, handleFormSubmit,
userAuth, userAuth,
}) => { }) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [characterLimit, setCharacterLimit] = useState(false); const [characterLimit, setCharacterLimit] = useState(false);
const { const {
@ -53,10 +52,10 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
}); });
const handleDescriptionFormSubmit = useCallback( const handleDescriptionFormSubmit = useCallback(
(formData: Partial<IIssue>) => { async (formData: Partial<IIssue>) => {
if (!formData.name || formData.name.length === 0 || formData.name.length > 255) return; if (!formData.name || formData.name.length === 0 || formData.name.length > 255) return;
handleFormSubmit({ await handleFormSubmit({
name: formData.name ?? "", name: formData.name ?? "",
description: formData.description ?? "", description: formData.description ?? "",
description_html: formData.description_html ?? "<p></p>", description_html: formData.description_html ?? "<p></p>",
@ -65,17 +64,19 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
[handleFormSubmit] [handleFormSubmit]
); );
const debounceHandler = useMemo( useEffect(() => {
() => debounce(handleSubmit(handleDescriptionFormSubmit), 2000), const alertUser = (e: BeforeUnloadEvent) => {
[handleSubmit, handleDescriptionFormSubmit] console.log("beforeunload");
); e.preventDefault();
e.returnValue = "";
return "Are you sure you want to leave?";
};
useEffect( window.addEventListener("beforeunload", alertUser);
() => () => { return () => {
debounceHandler.cancel(); window.removeEventListener("beforeunload", alertUser);
}, };
[debounceHandler] }, [isSubmitting]);
);
// reset form values // reset form values
useEffect(() => { useEffect(() => {
@ -95,19 +96,29 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
placeholder="Enter issue name" placeholder="Enter issue name"
value={watch("name")} value={watch("name")}
onFocus={() => setCharacterLimit(true)} onFocus={() => setCharacterLimit(true)}
onBlur={() => setCharacterLimit(false)} onBlur={() => {
setCharacterLimit(false);
setIsSubmitting(true);
handleSubmit(handleDescriptionFormSubmit)()
.then(() => {
setIsSubmitting(false);
})
.catch(() => {
setIsSubmitting(false);
});
}}
onChange={(e) => { onChange={(e) => {
setValue("name", e.target.value); setValue("name", e.target.value);
debounceHandler();
}} }}
required={true} required={true}
className="block px-3 py-2 text-xl className="min-h-10 block w-full resize-none
w-full overflow-hidden resize-none min-h-10 overflow-hidden rounded border-none bg-transparent
rounded border-none bg-transparent ring-0 focus:ring-1 focus:ring-theme outline-none" px-3 py-2 text-xl outline-none ring-0 focus:ring-1 focus:ring-theme"
role="textbox" role="textbox"
/> />
{characterLimit && ( {characterLimit && (
<div className="absolute bottom-0 right-0 text-xs bg-white p-1 rounded pointer-events-none z-[2]"> <div className="pointer-events-none absolute bottom-0 right-0 z-[2] rounded bg-white p-1 text-xs">
<span <span
className={`${ className={`${
watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : "" watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
@ -123,13 +134,21 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
<RemirrorRichTextEditor <RemirrorRichTextEditor
value={watch("description")} value={watch("description")}
placeholder="Describe the issue..." placeholder="Describe the issue..."
onJSONChange={(json) => { onBlur={() => {
setValue("description", json); setIsSubmitting(true);
debounceHandler(); handleSubmit(handleDescriptionFormSubmit)()
.then(() => {
setIsSubmitting(false);
})
.catch(() => {
setIsSubmitting(false);
});
}} }}
onJSONChange={(json) => setValue("description", json)}
onHTMLChange={(html) => setValue("description_html", html)} onHTMLChange={(html) => setValue("description_html", html)}
editable={!isNotAllowed} editable={!isNotAllowed}
/> />
<div className="text-right text-sm text-gray-500">{isSubmitting && "Saving..."}</div>
</div> </div>
); );
}; };

View File

@ -74,7 +74,7 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
}); });
const submitChanges = useCallback( const submitChanges = useCallback(
(formData: Partial<IIssue>) => { async (formData: Partial<IIssue>) => {
if (!workspaceSlug || !projectId || !issueId) return; if (!workspaceSlug || !projectId || !issueId) return;
mutate( mutate(
@ -87,7 +87,7 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
); );
const payload = { ...formData }; const payload = { ...formData };
issuesService await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload) .patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload)
.then((res) => { .then((res) => {
mutateIssueDetails(); mutateIssueDetails();