import { MutableRefObject, memo, useEffect, useRef, useState } from "react"; import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; import { observer } from "mobx-react-lite"; import { TIssue, IIssueDisplayProperties, IIssueMap } from "@plane/types"; // hooks import { ControlLink, DropIndicator, Tooltip } from "@plane/ui"; import RenderIfVisible from "@/components/core/render-if-visible-HOC"; import { cn } from "@/helpers/common.helper"; import { useApplication, useIssueDetail, useKanbanView, useProject } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; // components import { IssueProperties } from "../properties/all-properties"; import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC"; // ui // types // helper interface IssueBlockProps { peekIssueId?: string; issueId: string; issuesMap: IIssueMap; displayProperties: IIssueDisplayProperties | undefined; isDragDisabled: boolean; draggableId: string; updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined; quickActions: (issue: TIssue) => React.ReactNode; canEditProperties: (projectId: string | undefined) => boolean; scrollableContainerRef?: MutableRefObject; issueIds: string[]; //DO NOT REMOVE< needed to force render for virtualization } interface IssueDetailsBlockProps { issue: TIssue; displayProperties: IIssueDisplayProperties | undefined; updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined; quickActions: (issue: TIssue) => React.ReactNode; isReadOnly: boolean; } const KanbanIssueDetailsBlock: React.FC = observer((props: IssueDetailsBlockProps) => { const { issue, updateIssue, quickActions, isReadOnly, displayProperties } = props; // hooks const { isMobile } = usePlatformOS(); const { getProjectIdentifierById } = useProject(); const handleEventPropagation = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); }; return ( <>
{getProjectIdentifierById(issue.project_id)}-{issue.sequence_id}
{quickActions(issue)}
{issue?.is_draft ? ( {issue.name} ) : (
{issue.name}
)} ); }); export const KanbanIssueBlock: React.FC = memo((props) => { const { peekIssueId, issueId, issuesMap, displayProperties, isDragDisabled, updateIssue, quickActions, canEditProperties, scrollableContainerRef, issueIds, } = props; const cardRef = useRef(null); const { router: { workspaceSlug }, } = useApplication(); const { peekIssue, setPeekIssue } = useIssueDetail(); const handleIssuePeekOverview = (issue: TIssue) => workspaceSlug && issue && issue.project_id && issue.id && peekIssue?.issueId !== issue.id && setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id }); const issue = issuesMap[issueId]; const { setIsDragging: setIsKanbanDragging } = useKanbanView(); const [isDraggingOverBlock, setIsDraggingOverBlock] = useState(false); const [isCurrentBlockDragging, setIsCurrentBlockDragging] = useState(false); const canEditIssueProperties = canEditProperties(issue?.project_id); const isDragAllowed = !isDragDisabled && !issue?.tempId && canEditIssueProperties; // Make Issue block both as as Draggable and, // as a DropTarget for other issues being dragged to get the location of drop useEffect(() => { const element = cardRef.current; if (!element) return; return combine( draggable({ element, canDrag: () => isDragAllowed, getInitialData: () => ({ id: issue?.id, type: "ISSUE" }), onDragStart: () => { setIsCurrentBlockDragging(true); setIsKanbanDragging(true); }, onDrop: () => { setIsKanbanDragging(false); setIsCurrentBlockDragging(false); }, }), dropTargetForElements({ element, canDrop: (payload) => payload.source?.data?.id !== issue?.id, getData: () => ({ id: issue?.id, type: "ISSUE" }), onDragEnter: () => { setIsDraggingOverBlock(true); }, onDragLeave: () => { setIsDraggingOverBlock(false); }, onDrop: () => { setIsDraggingOverBlock(false); }, }) ); }, [cardRef?.current, issue?.id, setIsCurrentBlockDragging, setIsDraggingOverBlock]); if (!issue) return null; return ( <>
isDragAllowed && setIsCurrentBlockDragging(true)} > handleIssuePeekOverview(issue)} disabled={!!issue?.tempId} >
); }); KanbanIssueBlock.displayName = "KanbanIssueBlock";