import React, { useState } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { CalendarDays, LinkIcon, Signal, Tag, Trash2, Triangle, LayoutPanelTop } from "lucide-react"; // hooks import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { DeleteIssueModal, IssueLinkRoot, IssueRelationSelect, IssueCycleSelect, IssueModuleSelect, IssueParentSelect, IssueLabel, } from "components/issues"; import { IssueSubscription } from "./subscription"; import { EstimateDropdown, PriorityDropdown, ProjectMemberDropdown, StateDropdown } from "components/dropdowns"; // ui import { CustomDatePicker } from "components/ui"; // icons import { ContrastIcon, DiceIcon, DoubleCircleIcon, StateGroupIcon, UserGroupIcon } from "@plane/ui"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types import type { TIssueOperations } from "./root"; // fetch-keys import { EUserProjectRoles } from "constants/project"; type Props = { workspaceSlug: string; projectId: string; issueId: string; issueOperations: TIssueOperations; is_archived: boolean; is_editable: boolean; fieldsToShow?: ( | "state" | "assignee" | "priority" | "estimate" | "parent" | "blocker" | "blocked" | "startDate" | "dueDate" | "cycle" | "module" | "label" | "link" | "delete" | "all" | "subscribe" | "duplicate" | "relates_to" )[]; }; export const IssueDetailsSidebar: React.FC = observer((props) => { const { workspaceSlug, projectId, issueId, issueOperations, is_archived, is_editable, fieldsToShow = ["all"], } = props; // router const router = useRouter(); const { inboxIssueId } = router.query; // store hooks const { getProjectById } = useProject(); const { currentUser, membership: { currentProjectRole }, } = useUser(); const { projectStates } = useProjectState(); const { areEstimatesEnabledForCurrentProject } = useEstimate(); const { setToastAlert } = useToast(); const { issue: { getIssueById }, } = useIssueDetail(); // states const [deleteIssueModal, setDeleteIssueModal] = useState(false); const issue = getIssueById(issueId); if (!issue) return <>; const handleCopyText = () => { const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", message: "Issue link copied to clipboard.", }); }); }; const projectDetails = issue ? getProjectById(issue.project_id) : null; const showFirstSection = fieldsToShow.includes("all") || fieldsToShow.includes("state") || fieldsToShow.includes("assignee") || fieldsToShow.includes("priority") || fieldsToShow.includes("estimate"); const showSecondSection = fieldsToShow.includes("all") || fieldsToShow.includes("parent") || fieldsToShow.includes("blocker") || fieldsToShow.includes("blocked") || fieldsToShow.includes("dueDate"); const showThirdSection = fieldsToShow.includes("all") || fieldsToShow.includes("cycle") || fieldsToShow.includes("module"); const minDate = issue.start_date ? new Date(issue.start_date) : null; minDate?.setDate(minDate.getDate()); const maxDate = issue.target_date ? new Date(issue.target_date) : null; maxDate?.setDate(maxDate.getDate()); const isAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; const currentIssueState = projectStates?.find((s) => s.id === issue.state_id); return ( <> {workspaceSlug && projectId && issue && ( setDeleteIssueModal(false)} isOpen={deleteIssueModal} data={issue} onSubmit={async () => { await issueOperations.remove(workspaceSlug, projectId, issueId); router.push(`/${workspaceSlug}/projects/${projectId}/issues`); }} /> )}
{currentIssueState ? ( ) : inboxIssueId ? ( ) : null}

{projectDetails?.identifier}-{issue?.sequence_id}

{currentUser && !is_archived && (fieldsToShow.includes("all") || fieldsToShow.includes("subscribe")) && ( )} {/* {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && ( )} */} {/* {isAllowed && (fieldsToShow.includes("all") || fieldsToShow.includes("delete")) && ( )} */}
{showFirstSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("state")) && (

State

issueOperations.update(workspaceSlug, projectId, issueId, { state_id: val })} projectId={projectId?.toString() ?? ""} disabled={!isAllowed || !is_editable} buttonVariant="background-with-text" />
)} {(fieldsToShow.includes("all") || fieldsToShow.includes("assignee")) && (

Assignees

issueOperations.update(workspaceSlug, projectId, issueId, { assignee_ids: val }) } disabled={!isAllowed || !is_editable} projectId={projectId?.toString() ?? ""} placeholder="Assignees" multiple buttonVariant={ issue?.assignee_ids?.length > 0 ? "transparent-without-text" : "background-with-text" } buttonClassName={issue?.assignee_ids?.length > 0 ? "hover:bg-transparent px-0" : ""} />
)} {(fieldsToShow.includes("all") || fieldsToShow.includes("priority")) && (

Priority

issueOperations.update(workspaceSlug, projectId, issueId, { priority: val })} disabled={!isAllowed || !is_editable} buttonVariant="background-with-text" />
)} {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && areEstimatesEnabledForCurrentProject && (

Estimate

issueOperations.update(workspaceSlug, projectId, issueId, { estimate_point: val }) } projectId={projectId} disabled={!isAllowed || !is_editable} buttonVariant="background-with-text" />
)}
)} {showSecondSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("parent")) && (

Parent

)} {(fieldsToShow.includes("all") || fieldsToShow.includes("blocker")) && ( )} {(fieldsToShow.includes("all") || fieldsToShow.includes("blocked")) && ( )} {(fieldsToShow.includes("all") || fieldsToShow.includes("duplicate")) && ( )} {(fieldsToShow.includes("all") || fieldsToShow.includes("relates_to")) && ( )} {(fieldsToShow.includes("all") || fieldsToShow.includes("startDate")) && (

Start date

issueOperations.update(workspaceSlug, projectId, issueId, { start_date: val }) } className="border-none bg-custom-background-80" maxDate={maxDate ?? undefined} disabled={!isAllowed || !is_editable} />
)} {(fieldsToShow.includes("all") || fieldsToShow.includes("dueDate")) && (

Due date

issueOperations.update(workspaceSlug, projectId, issueId, { target_date: val }) } className="border-none bg-custom-background-80" minDate={minDate ?? undefined} disabled={!isAllowed || !is_editable} />
)}
)} {showThirdSection && (
{(fieldsToShow.includes("all") || fieldsToShow.includes("cycle")) && projectDetails?.cycle_view && (

Cycle

)} {(fieldsToShow.includes("all") || fieldsToShow.includes("module")) && projectDetails?.module_view && (

Module

)}
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("label")) && (

Label

)} {(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && ( )}
); });