import React, { useCallback, useEffect, useState } from "react"; // next import Link from "next/link"; import type { NextPage } from "next"; import { useRouter } from "next/router"; import dynamic from "next/dynamic"; // swr import useSWR, { mutate } from "swr"; // react hook form import { useForm } from "react-hook-form"; // headless ui import { Disclosure, Menu, Tab, Transition } from "@headlessui/react"; // fetch keys import { PROJECT_ISSUES_ACTIVITY, PROJECT_ISSUES_COMMENTS, PROJECT_ISSUES_LIST, } from "constants/fetch-keys"; // services import issuesServices from "lib/services/issues.service"; // common import { debounce } from "constants/common"; // hooks import useUser from "lib/hooks/useUser"; // hoc import withAuth from "lib/hoc/withAuthWrapper"; // layouts import AppLayout from "layouts/app-layout"; // components import CreateUpdateIssuesModal from "components/project/issues/create-update-issue-modal"; import IssueCommentSection from "components/project/issues/issue-detail/comment/IssueCommentSection"; import AddAsSubIssue from "components/project/issues/issue-detail/add-as-sub-issue"; import ConfirmIssueDeletion from "components/project/issues/confirm-issue-deletion"; import IssueDetailSidebar from "components/project/issues/issue-detail/issue-detail-sidebar"; import IssueActivitySection from "components/project/issues/issue-detail/activity"; // ui import { Spinner, TextArea, HeaderButton, Breadcrumbs, BreadcrumbItem } from "ui"; // icons import { ChevronLeftIcon, ChevronRightIcon, EllipsisHorizontalIcon, PlusIcon, } from "@heroicons/react/24/outline"; // types import { IIssue, IIssueComment, IssueResponse } from "types"; const RichTextEditor = dynamic(() => import("components/lexical/editor"), { ssr: false, }); const IssueDetail: NextPage = () => { const [deleteIssueModal, setDeleteIssueModal] = useState(false); const [isOpen, setIsOpen] = useState(false); const [isAddAsSubIssueOpen, setIsAddAsSubIssueOpen] = useState(false); const [issueDetail, setIssueDetail] = useState(undefined); const [preloadedData, setPreloadedData] = useState< (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined >(undefined); const [issueDescriptionValue, setIssueDescriptionValue] = useState(""); const router = useRouter(); const { issueId, projectId } = router.query; const { activeWorkspace, activeProject, issues, mutateIssues, states } = useUser(); const handleDescriptionChange: any = (value: any) => { console.log(value); setIssueDescriptionValue(value); }; const { register, formState: { errors }, handleSubmit, reset, control, watch, } = useForm({ defaultValues: { name: "", description: "", state: "", assignees_list: [], priority: "low", blockers_list: [], blocked_list: [], target_date: new Date().toString(), issue_cycle: null, labels_list: [], }, }); const { data: issueActivities } = useSWR( activeWorkspace && projectId && issueId ? PROJECT_ISSUES_ACTIVITY : null, activeWorkspace && projectId && issueId ? () => issuesServices.getIssueActivities( activeWorkspace.slug, projectId as string, issueId as string ) : null ); const { data: issueComments } = useSWR( activeWorkspace && projectId && issueId ? PROJECT_ISSUES_COMMENTS(issueId as string) : null, activeWorkspace && projectId && issueId ? () => issuesServices.getIssueComments( activeWorkspace.slug, projectId as string, issueId as string ) : null ); const submitChanges = useCallback( (formData: Partial) => { if (!activeWorkspace || !activeProject || !issueId) return; mutateIssues( (prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((issue) => { if (issue.id === issueId) { return { ...issue, ...formData }; } return issue; }), }), false ); const payload = { ...formData, // description: formData.description ? JSON.parse(formData.description) : null, }; issuesServices .patchIssue(activeWorkspace.slug, projectId as string, issueId as string, payload) .then((response) => { mutateIssues((prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((issue) => { if (issue.id === issueId) { return { ...issue, ...response }; } return issue; }), })); }) .catch((error) => { console.log(error); }); }, [activeProject, activeWorkspace, issueId, projectId, mutateIssues] ); useEffect(() => { if (issueDetail) reset({ ...issueDetail, // description: JSON.stringify(issueDetail.description), blockers_list: issueDetail.blockers_list ?? issueDetail.blocker_issues?.map((issue) => issue.blocker_issue_detail?.id), blocked_list: issueDetail.blocked_list ?? issueDetail.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id), assignees_list: issueDetail.assignees_list ?? issueDetail.assignee_details?.map((user) => user.id), labels_list: issueDetail.labels_list ?? issueDetail.labels, labels: issueDetail.labels_list ?? issueDetail.labels, }); }, [issueDetail, reset]); useEffect(() => { const issueDetail = issues?.results.find((issue) => issue.id === issueId); setIssueDetail(issueDetail); }, [issueId, issues]); const prevIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) - 1]; const nextIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) + 1]; const subIssues = (issues && issues.results.filter((i) => i.parent === issueId)) ?? []; const siblingIssues = issueDetail && issues?.results.filter((i) => i.parent === issueDetail.parent && i.id !== issueId); const handleSubIssueRemove = (issueId: string) => { if (activeWorkspace && activeProject) { issuesServices .patchIssue(activeWorkspace.slug, activeProject.id, issueId, { parent: null }) .then((res) => { mutate( PROJECT_ISSUES_LIST(activeWorkspace.slug, activeProject.id), (prevData) => ({ ...(prevData as IssueResponse), results: (prevData?.results ?? []).map((p) => p.id === issueId ? { ...p, ...res } : p ), }), false ); }) .catch((e) => { console.log(e); }); } }; return ( } right={
{ if (!prevIssue) return; router.push(`/projects/${prevIssue.project}/issues/${prevIssue.id}`); }} /> { if (!nextIssue) return; router.push(`/projects/${nextIssue.project}/issues/${nextIssue?.id}`); }} position="reverse" />
} > setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issueDetail} /> {issueDetail && activeProject ? (
{issueDetail.parent !== null && issueDetail.parent !== "" ? ( ) : null}