import React, { useState } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Dialog, Transition } from "@headlessui/react"; // hooks import { useIssues, useProject } from "hooks/store"; import useToast from "hooks/use-toast"; import useLocalStorage from "hooks/use-local-storage"; // components import { DraftIssueLayout } from "./draft-issue-layout"; import { IssueFormRoot } from "./form"; // types import type { TIssue } from "@plane/types"; // constants import { EIssuesStoreType } from "constants/issue"; export interface IssuesModalProps { data?: Partial; isOpen: boolean; onClose: () => void; onSubmit?: (res: TIssue) => Promise; withDraftIssueWrapper?: boolean; } export const CreateUpdateIssueModal: React.FC = observer((props) => { const { data, isOpen, onClose, onSubmit, withDraftIssueWrapper = true } = props; // states const [changesMade, setChangesMade] = useState | null>(null); const [createMore, setCreateMore] = useState(false); // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; // store hooks const { workspaceProjectIds } = useProject(); const { issues: { createIssue, updateIssue }, } = useIssues(EIssuesStoreType.PROJECT); const { issues: { addIssueToCycle }, } = useIssues(EIssuesStoreType.CYCLE); const { issues: { addIssueToModule }, } = useIssues(EIssuesStoreType.MODULE); // toast alert const { setToastAlert } = useToast(); // local storage const { setValue: setLocalStorageDraftIssue } = useLocalStorage("draftedIssue", {}); const handleCreateMoreToggleChange = (value: boolean) => { setCreateMore(value); }; const handleClose = (saveDraftIssueInLocalStorage?: boolean) => { if (changesMade && saveDraftIssueInLocalStorage) { const draftIssue = JSON.stringify(changesMade); setLocalStorageDraftIssue(draftIssue); } onClose(); }; const handleCreateIssue = async (payload: Partial): Promise => { if (!workspaceSlug || !payload.project_id) return undefined; try { const response = await createIssue(workspaceSlug.toString(), payload.project_id, payload); setToastAlert({ type: "success", title: "Success!", message: "Issue created successfully.", }); !createMore && handleClose(); return response; } catch (error) { setToastAlert({ type: "error", title: "Error!", message: "Issue could not be created. Please try again.", }); } }; const handleUpdateIssue = async (payload: Partial): Promise => { if (!workspaceSlug || !payload.project_id || !data?.id) return undefined; try { const response = await updateIssue(workspaceSlug.toString(), payload.project_id, data.id, payload); setToastAlert({ type: "success", title: "Success!", message: "Issue updated successfully.", }); handleClose(); return response; } catch (error) { setToastAlert({ type: "error", title: "Error!", message: "Issue could not be created. Please try again.", }); } }; const handleFormSubmit = async (formData: Partial) => { if (!workspaceSlug || !formData.project_id) return; const payload: Partial = { ...formData, description_html: formData.description_html ?? "

", }; let res: TIssue | undefined = undefined; if (!data?.id) res = await handleCreateIssue(payload); else res = await handleUpdateIssue(payload); // add issue to cycle if cycle is selected, and cycle is different from current cycle if (formData.cycle_id && res && (!data?.id || formData.cycle_id !== data?.cycle_id)) await addIssueToCycle(workspaceSlug.toString(), formData.project_id, formData.cycle_id, [res.id]); // add issue to module if module is selected, and module is different from current module if (formData.module_id && res && (!data?.id || formData.module_id !== data?.module_id)) await addIssueToModule(workspaceSlug.toString(), formData.project_id, formData.module_id, [res.id]); if (res != undefined && onSubmit) await onSubmit(res); }; const handleFormChange = (formData: Partial | null) => setChangesMade(formData); // don't open the modal if there are no projects if (!workspaceProjectIds || workspaceProjectIds.length === 0) return null; // if project id is present in the router query, use that as the selected project id, otherwise use the first project id const selectedProjectId = projectId ? projectId.toString() : workspaceProjectIds[0]; return ( handleClose(true)}>
{withDraftIssueWrapper ? ( ) : ( handleClose(false)} isCreateMoreToggleEnabled={createMore} onCreateMoreToggleChange={handleCreateMoreToggleChange} onSubmit={handleFormSubmit} projectId={selectedProjectId} /> )}
); });