import { TiptapEditor } from "@plane/editor"; 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"; import fileService from "@/services/file.service"; 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.issue_relations; delete payload.related_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 uploadFile={fileService.uploadFile} deleteFile={fileService.deleteImage} 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;