import React, { useCallback, useEffect, useState } from "react";
// next
import Link from "next/link";
import dynamic from "next/dynamic";
import type { NextPage } from "next";
import { useRouter } from "next/router";
// swr
import { 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_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 AddAsSubIssue from "components/project/issues/issue-detail/add-as-sub-issue";
import CreateUpdateIssuesModal from "components/project/issues/create-update-issue-modal";
import IssueDetailSidebar from "components/project/issues/issue-detail/issue-detail-sidebar";
import IssueCommentSection from "components/project/issues/issue-detail/comment/IssueCommentSection";
const IssueActivitySection = dynamic(
() => import("components/project/issues/issue-detail/activity"),
{
loading: () => (
),
ssr: false,
}
);
// ui
import { Spinner, TextArea, HeaderButton, Breadcrumbs } from "ui";
// icons
import {
ChevronLeftIcon,
ChevronRightIcon,
EllipsisHorizontalIcon,
PlusIcon,
} from "@heroicons/react/24/outline";
// types
import { IIssue, IssueResponse } from "types";
const RichTextEditor = dynamic(() => import("components/lexical/editor"), {
ssr: false,
});
const defaultValues = {
name: "",
description: "",
state: "",
assignees_list: [],
priority: "low",
blockers_list: [],
blocked_list: [],
target_date: new Date().toString(),
issue_cycle: null,
labels_list: [],
};
const IssueDetail: NextPage = () => {
const router = useRouter();
const { issueId, projectId } = router.query;
const { activeWorkspace, activeProject, issues, mutateIssues } = useUser();
const issueDetail = issues?.results?.find((issue) => issue.id === issueId);
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 [isOpen, setIsOpen] = useState(false);
const [isAddAsSubIssueOpen, setIsAddAsSubIssueOpen] = useState(false);
const [preloadedData, setPreloadedData] = useState<
(Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined
>(undefined);
const [issueDescriptionValue, setIssueDescriptionValue] = useState("");
const handleDescriptionChange: any = (value: any) => {
console.log(value);
setIssueDescriptionValue(value);
};
const {
register,
formState: { errors },
handleSubmit,
reset,
control,
watch,
} = useForm({
defaultValues,
});
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]);
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"
/>
}
>
{isOpen && (
)}
{isAddAsSubIssueOpen && (
)}
{issueDetail && activeProject ? (
{issueDetail.parent !== null && issueDetail.parent !== "" ? (
) : null}
{subIssues && subIssues.length > 0 ? (
{({ open }) => (
<>
Sub-issues{" "}
{subIssues.length}
{open ? (
) : null}
{subIssues.map((subIssue) => (
))}
>
)}
) : (
)}
{["Comments", "Activity"].map((item) => (
`px-3 py-1 text-sm rounded-md border-2 border-gray-700 ${
selected ? "bg-gray-700 text-white" : ""
}`
}
>
{item}
))}
{/* TODO add flex-grow, if needed */}
) : (
)}
);
};
export default withAuth(IssueDetail);