import { FC, useRef, useState } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { MoveRight, MoveDiagonal, Link2, Trash2 } from "lucide-react"; // hooks import useOutsideClickDetector from "hooks/use-outside-click-detector"; import useKeypress from "hooks/use-keypress"; // store hooks import { useIssueDetail, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; // components import { DeleteArchivedIssueModal, DeleteIssueModal, IssueActivity, IssueSubscription, IssueUpdateStatus, PeekOverviewIssueDetails, PeekOverviewProperties, TIssueOperations, } from "components/issues"; // ui import { CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon, Spinner } from "@plane/ui"; // helpers import { copyUrlToClipboard } from "helpers/string.helper"; interface IIssueView { workspaceSlug: string; projectId: string; issueId: string; isLoading?: boolean; is_archived: boolean; disabled?: boolean; issueOperations: TIssueOperations; } type TPeekModes = "side-peek" | "modal" | "full-screen"; const PEEK_OPTIONS: { key: TPeekModes; icon: any; title: string }[] = [ { key: "side-peek", icon: SidePanelIcon, title: "Side Peek", }, { key: "modal", icon: CenterPanelIcon, title: "Modal", }, { key: "full-screen", icon: FullScreenPanelIcon, title: "Full Screen", }, ]; export const IssueView: FC = observer((props) => { const { workspaceSlug, projectId, issueId, isLoading, is_archived, disabled = false, issueOperations } = props; // router const router = useRouter(); // states const [peekMode, setPeekMode] = useState("side-peek"); const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); // ref const issuePeekOverviewRef = useRef(null); // store hooks const { activity, setPeekIssue, isAnyModalOpen, isDeleteIssueModalOpen, toggleDeleteIssueModal } = useIssueDetail(); const { currentUser } = useUser(); const { issue: { getIssueById }, } = useIssueDetail(); const { setToastAlert } = useToast(); // derived values const issueActivity = activity.getActivitiesByIssueId(issueId); const currentMode = PEEK_OPTIONS.find((m) => m.key === peekMode); const issue = getIssueById(issueId); const removeRoutePeekId = () => { setPeekIssue(undefined); }; useOutsideClickDetector(issuePeekOverviewRef, () => !isAnyModalOpen && removeRoutePeekId()); const redirectToIssueDetail = () => { router.push({ pathname: `/${workspaceSlug}/projects/${projectId}/${is_archived ? "archived-issues" : "issues"}/${issueId}`, }); removeRoutePeekId(); }; const handleCopyText = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); copyUrlToClipboard( `${workspaceSlug}/projects/${projectId}/${is_archived ? "archived-issues" : "issues"}/${issueId}` ).then(() => { setToastAlert({ type: "success", title: "Link Copied!", message: "Issue link copied to clipboard.", }); }); }; const handleKeyDown = () => !isAnyModalOpen && removeRoutePeekId(); useKeypress("Escape", handleKeyDown); return ( <> {issue && !is_archived && ( { toggleDeleteIssueModal(false); removeRoutePeekId(); }} data={issue} onSubmit={() => issueOperations.remove(workspaceSlug, projectId, issueId)} /> )} {issue && is_archived && ( toggleDeleteIssueModal(false)} onSubmit={() => issueOperations.remove(workspaceSlug, projectId, issueId)} /> )}
{issueId && (
{/* header */}
{currentMode && (
setPeekMode(val)} customButton={ } > {PEEK_OPTIONS.map((mode) => (
{mode.title}
))}
)}
{currentUser && !is_archived && ( )} {!disabled && ( )}
{/* content */}
{isLoading && !issue ? (
) : ( issue && ( <> {["side-peek", "modal"].includes(peekMode) ? (
{is_archived && (
)} setIsSubmitting(value)} /> {/* */}
) : (
setIsSubmitting(value)} /> {/* */}
)} ) )}
)}
); });