import { FC, ReactNode, useState } from "react"; import { useRouter } from "next/router"; import { PanelRightOpen, Square, SquareCode, MoveRight, MoveDiagonal, Bell, Link2, Trash2 } from "lucide-react"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; // components import { PeekOverviewIssueDetails } from "./issue-detail"; import { PeekOverviewProperties } from "./properties"; import { IssueComment } from "./activity"; import { Button, CustomSelect, FullScreenPeekIcon, ModalPeekIcon, SidePeekIcon } from "@plane/ui"; import { DeleteIssueModal } from "../delete-issue-modal"; // types import { IIssue } from "types"; import { RootStore } from "store/root"; // hooks import { useMobxStore } from "lib/mobx/store-provider"; import useToast from "hooks/use-toast"; // helpers import { copyUrlToClipboard } from "helpers/string.helper"; interface IIssueView { workspaceSlug: string; projectId: string; issueId: string; issueUpdate: (issue: Partial) => void; issueReactionCreate: (reaction: string) => void; issueReactionRemove: (reaction: string) => void; issueCommentCreate: (comment: any) => void; issueCommentUpdate: (comment: any) => void; issueCommentRemove: (commentId: string) => void; issueCommentReactionCreate: (commentId: string, reaction: string) => void; issueCommentReactionRemove: (commentId: string, reaction: string) => void; issueSubscriptionCreate: () => void; issueSubscriptionRemove: () => void; handleDeleteIssue: () => Promise; children: ReactNode; } type TPeekModes = "side-peek" | "modal" | "full-screen"; const peekOptions: { key: TPeekModes; icon: any; title: string }[] = [ { key: "side-peek", icon: SidePeekIcon, title: "Side Peek", }, { key: "modal", icon: ModalPeekIcon, title: "Modal", }, { key: "full-screen", icon: FullScreenPeekIcon, title: "Full Screen", }, ]; export const IssueView: FC = observer((props) => { const { workspaceSlug, projectId, issueId, issueUpdate, issueReactionCreate, issueReactionRemove, issueCommentCreate, issueCommentUpdate, issueCommentRemove, issueCommentReactionCreate, issueCommentReactionRemove, issueSubscriptionCreate, issueSubscriptionRemove, handleDeleteIssue, children, } = props; const router = useRouter(); const { peekIssueId } = router.query as { peekIssueId: string }; const { user: userStore, issueDetail: issueDetailStore }: RootStore = useMobxStore(); const [peekMode, setPeekMode] = useState("side-peek"); const [deleteIssueModal, setDeleteIssueModal] = useState(false); const { setToastAlert } = useToast(); const handleCopyText = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/issues/${peekIssueId}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", message: "Issue link copied to clipboard.", }); }); }; const updateRoutePeekId = () => { if (issueId != peekIssueId) { const { query } = router; router.push({ pathname: router.pathname, query: { ...query, peekIssueId: issueId }, }); } }; const removeRoutePeekId = () => { const { query } = router; if (query.peekIssueId) { delete query.peekIssueId; router.push({ pathname: router.pathname, query: { ...query }, }); } }; const redirectToIssueDetail = () => { router.push({ pathname: `/${workspaceSlug}/projects/${projectId}/issues/${issueId}`, }); }; useSWR( workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId ? `ISSUE_PEEK_OVERVIEW_${workspaceSlug}_${projectId}_${peekIssueId}` : null, async () => { if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId) { await issueDetailStore.fetchPeekIssueDetails(workspaceSlug, projectId, issueId); } } ); useSWR( workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId ? `ISSUE_PEEK_OVERVIEW_SUBSCRIPTION_${workspaceSlug}_${projectId}_${peekIssueId}` : null, async () => { if (workspaceSlug && projectId && issueId && peekIssueId && issueId === peekIssueId) { await issueDetailStore.fetchIssueSubscription(workspaceSlug, projectId, issueId); } } ); const issue = issueDetailStore.getIssue; const issueReactions = issueDetailStore.getIssueReactions; const issueComments = issueDetailStore.getIssueComments; const issueSubscription = issueDetailStore.getIssueSubscription; const user = userStore?.currentUser; const currentMode = peekOptions.find((m) => m.key === peekMode); return ( <> {issue && ( setDeleteIssueModal(false)} data={issue} onSubmit={handleDeleteIssue} /> )}
{children}
{issueId === peekIssueId && (
{/* header */}
{currentMode && (
setPeekMode(val)} customButton={ } > {peekOptions.map((mode) => (
{mode.title}
))}
)}
{/* content */}
{issueDetailStore?.loader && !issue ? (
Loading...
) : ( issue && ( <> {["side-peek", "modal"].includes(peekMode) ? (
) : (
)} ) )}
)}
); });