feat: editor for issue description (#2038)

This commit is contained in:
Lakhan Baheti 2023-09-01 10:59:17 +05:30 committed by GitHub
parent 099bce87b5
commit eab1d9329b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -0,0 +1,192 @@
import { TipTapEditor } from "components/tiptap";
import type { NextPage } from "next";
import { useCallback, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import issuesService from "services/issues.service";
import { ICurrentUserResponse, IIssue } from "types";
import useReloadConfirmations from "hooks/use-reload-confirmation";
import { Spinner } from "components/ui";
import Image404 from "public/404.svg";
import DefaultLayout from "layouts/default-layout";
import Image from "next/image";
import userService from "services/user.service";
import { useRouter } from "next/router";
const Editor: NextPage = () => {
const [user, setUser] = useState<ICurrentUserResponse | undefined>();
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
const [isLoading, setIsLoading] = useState("false");
const { setShowAlert } = useReloadConfirmations();
const [cookies, setCookies] = useState<any>({});
const [issueDetail, setIssueDetail] = useState<IIssue | null>(null);
const router = useRouter();
const { editable } = router.query;
const {
handleSubmit,
watch,
setValue,
control,
formState: { errors },
} = useForm<IIssue>({
defaultValues: {
name: "",
description: "",
description_html: "",
},
});
const getCookies = () => {
const cookies = document.cookie.split(";");
const cookieObj: any = {};
cookies.forEach((cookie) => {
const cookieArr = cookie.split("=");
cookieObj[cookieArr[0].trim()] = cookieArr[1];
});
setCookies(cookieObj);
return cookieObj;
};
const getIssueDetail = async (cookiesData: any) => {
try {
setIsLoading("true");
const userData = await userService.currentUser();
setUser(userData);
const issueDetail = await issuesService.retrieve(
cookiesData.MOBILE_slug,
cookiesData.MOBILE_project_id,
cookiesData.MOBILE_issue_id
);
setIssueDetail(issueDetail);
setIsLoading("false");
setValue("description_html", issueDetail.description_html);
setValue("description", issueDetail.description);
} catch (e) {
setIsLoading("error");
console.log(e);
}
};
useEffect(() => {
const cookiesData = getCookies();
getIssueDetail(cookiesData);
}, []);
useEffect(() => {
if (isSubmitting === "submitted") {
setShowAlert(false);
setTimeout(async () => {
setIsSubmitting("saved");
}, 2000);
} else if (isSubmitting === "submitting") {
setShowAlert(true);
}
}, [isSubmitting, setShowAlert]);
const submitChanges = async (
formData: Partial<IIssue>,
workspaceSlug: string,
projectId: string,
issueId: string
) => {
if (!workspaceSlug || !projectId || !issueId) return;
const payload: Partial<IIssue> = {
...formData,
};
delete payload.blocker_issues;
delete payload.blocked_issues;
await issuesService
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, payload, user)
.catch((e) => {
console.log(e);
});
};
const handleDescriptionFormSubmit = useCallback(
async (formData: Partial<IIssue>) => {
if (!formData) return;
await submitChanges(
{
name: issueDetail?.name ?? "",
description: formData.description ?? "",
description_html: formData.description_html ?? "<p></p>",
},
cookies.MOBILE_slug,
cookies.MOBILE_project_id,
cookies.MOBILE_issue_id
);
},
[submitChanges]
);
return isLoading === "error" ? (
<ErrorEncountered />
) : isLoading === "true" ? (
<div className="grid place-items-center h-screen w-full">
<Spinner />
</div>
) : (
<div className="flex blur-none shadow-none backdrop:backdrop-blur-none justify-center items-center">
<Controller
name="description_html"
control={control}
render={({ field: { value, onChange } }) => (
<TipTapEditor
borderOnFocus={false}
value={
!value ||
value === "" ||
(typeof value === "object" && Object.keys(value).length === 0)
? watch("description_html")
: value
}
editable={editable === "true"}
noBorder={true}
workspaceSlug={cookies.MOBILE_slug ?? ""}
debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting}
customClassName="min-h-[150px] shadow-sm"
editorContentCustomClassNames="pb-9"
onChange={(description: Object, description_html: string) => {
setShowAlert(true);
setIsSubmitting("submitting");
onChange(description_html);
setValue("description", description);
handleSubmit(handleDescriptionFormSubmit)().finally(() => {
setIsSubmitting("submitted");
});
}}
/>
)}
/>
<div
className={`absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center ${
isSubmitting === "saved" ? "fadeOut" : "fadeIn"
}`}
>
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
</div>
</div>
);
};
const ErrorEncountered: NextPage = () => (
<DefaultLayout>
<div className="grid max-h-fit place-items-center p-4">
<div className="space-y-8 text-center">
<div className="relative mx-auto h-40 w-40 lg:h-40 lg:w-40">
<Image src={Image404} layout="fill" alt="404- Page not found" />
</div>
<div className="space-y-2">
<h3 className="text-lg font-semibold">Oops! Something went wrong.</h3>
</div>
</div>
</div>
</DefaultLayout>
);
export default Editor;