import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // react-hook-form import { useForm } from "react-hook-form"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services import projectService from "services/project.service"; import modulesService from "services/modules.service"; import issuesService from "services/issues.service"; // hooks import useUser from "hooks/use-user"; import useToast from "hooks/use-toast"; // components import { IssueForm } from "components/issues"; // types import type { IIssue, IssueResponse } from "types"; // fetch keys import { PROJECT_ISSUES_DETAILS, PROJECT_ISSUES_LIST, CYCLE_ISSUES, USER_ISSUE, PROJECTS_LIST, MODULE_ISSUES, SUB_ISSUES, } from "constants/fetch-keys"; export interface IssuesModalProps { isOpen: boolean; handleClose: () => void; data?: IIssue | null; prePopulateData?: Partial; isUpdatingSingleIssue?: boolean; } export const CreateUpdateIssueModal: React.FC = ({ isOpen, handleClose, data, prePopulateData, isUpdatingSingleIssue = false, }) => { // states const [createMore, setCreateMore] = useState(false); const [activeProject, setActiveProject] = useState(null); const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string }; const { user } = useUser(); const { setToastAlert } = useToast(); const { data: issues } = useSWR( workspaceSlug && activeProject ? PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? "") : null, workspaceSlug && activeProject ? () => issuesService.getIssues(workspaceSlug as string, activeProject ?? "") : null ); const { data: projects } = useSWR( workspaceSlug ? PROJECTS_LIST(workspaceSlug as string) : null, workspaceSlug ? () => projectService.getProjects(workspaceSlug as string) : null ); const { setError } = useForm({ mode: "all", reValidateMode: "onChange", }); useEffect(() => { if (projects && projects.length > 0) setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null); }, [projectId, projects]); const addIssueToCycle = async (issueId: string, cycleId: string) => { if (!workspaceSlug || !projectId) return; await issuesService .addIssueToCycle(workspaceSlug as string, activeProject ?? "", cycleId, { issues: [issueId], }) .then((res) => { mutate(CYCLE_ISSUES(cycleId)); if (isUpdatingSingleIssue) { mutate( PROJECT_ISSUES_DETAILS, (prevData) => ({ ...(prevData as IIssue), sprints: cycleId }), false ); } else mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? ""), (prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((issue) => { if (issue.id === res.id) return { ...issue, sprints: cycleId }; return issue; }), }), false ); }) .catch((err) => { console.log(err); }); }; const addIssueToModule = async (issueId: string, moduleId: string) => { if (!workspaceSlug || !projectId) return; await modulesService .addIssuesToModule(workspaceSlug as string, activeProject ?? "", moduleId as string, { issues: [issueId], }) .then((res) => { console.log(res); mutate(MODULE_ISSUES(moduleId as string)); }) .catch((e) => console.log(e)); }; const createIssue = async (payload: Partial) => { await issuesService .createIssues(workspaceSlug as string, activeProject ?? "", payload) .then((res) => { mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? "")); if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); if (!createMore) handleClose(); setToastAlert({ title: "Success", type: "success", message: "Issue created successfully", }); if (payload.assignees_list?.some((assignee) => assignee === user?.id)) mutate(USER_ISSUE); if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); }) .catch((err) => { if (err.detail) { setToastAlert({ title: "Join the project.", type: "error", message: "Click select to join from projects page to start making changes", }); } Object.keys(err).map((key) => { const message = err[key]; if (!message) return; setError(key as keyof IIssue, { message: Array.isArray(message) ? message.join(", ") : message, }); }); }); }; const updateIssue = async (payload: Partial) => { await issuesService .updateIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload) .then((res) => { if (isUpdatingSingleIssue) { mutate(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false); } else mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? ""), (prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((issue) => { if (issue.id === res.id) return { ...issue, ...res }; return issue; }), }) ); if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (!createMore) handleClose(); setToastAlert({ title: "Success", type: "success", message: "Issue updated successfully", }); }) .catch((err) => { Object.keys(err).map((key) => { setError(key as keyof IIssue, { message: err[key].join(", ") }); }); }); }; const handleFormSubmit = async (formData: Partial) => { if (!workspaceSlug || !activeProject) return; const payload: Partial = { ...formData, description: formData.description ? formData.description : "", description_html: formData.description_html ? formData.description_html : "

", }; if (!data) await createIssue(payload); else await updateIssue(payload); }; return (
); };