2023-08-11 10:29:13 +00:00
|
|
|
import { FC } from "react";
|
2023-08-28 07:55:47 +00:00
|
|
|
// hooks
|
2024-01-30 14:42:39 +00:00
|
|
|
import { useIssueDetail } from "hooks/store";
|
2023-08-28 07:55:47 +00:00
|
|
|
import { useChart } from "../hooks";
|
2023-08-11 10:29:13 +00:00
|
|
|
// helpers
|
2024-01-30 08:55:15 +00:00
|
|
|
import { ChartAddBlock, ChartDraggable } from "components/gantt-chart";
|
2024-01-02 09:15:51 +00:00
|
|
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
2024-01-30 14:42:39 +00:00
|
|
|
import { cn } from "helpers/common.helper";
|
2023-08-11 10:29:13 +00:00
|
|
|
// types
|
|
|
|
import { IBlockUpdateData, IGanttBlock } from "../types";
|
|
|
|
|
2023-12-10 10:18:10 +00:00
|
|
|
export type GanttChartBlocksProps = {
|
2023-08-11 10:29:13 +00:00
|
|
|
itemsContainerWidth: number;
|
|
|
|
blocks: IGanttBlock[] | null;
|
2023-11-02 10:32:34 +00:00
|
|
|
blockToRender: (data: any) => React.ReactNode;
|
2023-08-11 10:29:13 +00:00
|
|
|
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
|
2023-08-28 07:55:47 +00:00
|
|
|
enableBlockLeftResize: boolean;
|
|
|
|
enableBlockRightResize: boolean;
|
|
|
|
enableBlockMove: boolean;
|
2024-01-30 08:55:15 +00:00
|
|
|
showAllBlocks: boolean;
|
2023-12-10 10:18:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export const GanttChartBlocks: FC<GanttChartBlocksProps> = (props) => {
|
|
|
|
const {
|
|
|
|
itemsContainerWidth,
|
|
|
|
blocks,
|
|
|
|
blockToRender,
|
|
|
|
blockUpdateHandler,
|
|
|
|
enableBlockLeftResize,
|
|
|
|
enableBlockRightResize,
|
|
|
|
enableBlockMove,
|
2024-01-30 08:55:15 +00:00
|
|
|
showAllBlocks,
|
2023-12-10 10:18:10 +00:00
|
|
|
} = props;
|
|
|
|
|
2023-08-28 07:55:47 +00:00
|
|
|
const { activeBlock, dispatch } = useChart();
|
2024-01-30 14:42:39 +00:00
|
|
|
const { peekIssue } = useIssueDetail();
|
2023-08-28 07:55:47 +00:00
|
|
|
|
|
|
|
// update the active block on hover
|
|
|
|
const updateActiveBlock = (block: IGanttBlock | null) => {
|
|
|
|
dispatch({
|
|
|
|
type: "PARTIAL_UPDATE",
|
|
|
|
payload: {
|
|
|
|
activeBlock: block,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-08-11 10:29:13 +00:00
|
|
|
const handleChartBlockPosition = (
|
|
|
|
block: IGanttBlock,
|
|
|
|
totalBlockShifts: number,
|
2023-08-28 07:55:47 +00:00
|
|
|
dragDirection: "left" | "right" | "move"
|
2023-08-11 10:29:13 +00:00
|
|
|
) => {
|
2024-01-30 08:55:15 +00:00
|
|
|
if (!block.start_date || !block.target_date) return;
|
|
|
|
|
2023-08-28 07:55:47 +00:00
|
|
|
const originalStartDate = new Date(block.start_date);
|
|
|
|
const updatedStartDate = new Date(originalStartDate);
|
|
|
|
|
|
|
|
const originalTargetDate = new Date(block.target_date);
|
|
|
|
const updatedTargetDate = new Date(originalTargetDate);
|
|
|
|
|
|
|
|
// update the start date on left resize
|
2023-11-02 10:32:34 +00:00
|
|
|
if (dragDirection === "left") updatedStartDate.setDate(originalStartDate.getDate() - totalBlockShifts);
|
2023-08-28 07:55:47 +00:00
|
|
|
// update the target date on right resize
|
2023-11-02 10:32:34 +00:00
|
|
|
else if (dragDirection === "right") updatedTargetDate.setDate(originalTargetDate.getDate() + totalBlockShifts);
|
2023-08-28 07:55:47 +00:00
|
|
|
// update both the dates on x-axis move
|
|
|
|
else if (dragDirection === "move") {
|
|
|
|
updatedStartDate.setDate(originalStartDate.getDate() + totalBlockShifts);
|
|
|
|
updatedTargetDate.setDate(originalTargetDate.getDate() + totalBlockShifts);
|
2023-08-11 10:29:13 +00:00
|
|
|
}
|
|
|
|
|
2023-08-28 07:55:47 +00:00
|
|
|
// call the block update handler with the updated dates
|
2023-08-11 10:29:13 +00:00
|
|
|
blockUpdateHandler(block.data, {
|
2024-01-02 09:15:51 +00:00
|
|
|
start_date: renderFormattedPayloadDate(updatedStartDate) ?? undefined,
|
|
|
|
target_date: renderFormattedPayloadDate(updatedTargetDate) ?? undefined,
|
2023-08-11 10:29:13 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className="relative z-[5] mt-[72px] h-full overflow-hidden overflow-y-auto"
|
|
|
|
style={{ width: `${itemsContainerWidth}px` }}
|
|
|
|
>
|
2023-08-28 07:55:47 +00:00
|
|
|
{blocks &&
|
|
|
|
blocks.length > 0 &&
|
2024-01-30 08:55:15 +00:00
|
|
|
blocks.map((block) => {
|
|
|
|
// hide the block if it doesn't have start and target dates and showAllBlocks is false
|
|
|
|
if (!showAllBlocks && !(block.start_date && block.target_date)) return;
|
|
|
|
|
|
|
|
const isBlockVisibleOnChart = block.start_date && block.target_date;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={`block-${block.id}`}
|
2024-01-30 14:42:39 +00:00
|
|
|
className={cn(
|
|
|
|
"h-11",
|
|
|
|
{ "rounded bg-custom-background-80": activeBlock?.id === block.id },
|
|
|
|
{
|
|
|
|
"rounded-l border border-r-0 border-custom-primary-70 hover:border-custom-primary-70":
|
|
|
|
peekIssue?.issueId === block.data.id,
|
|
|
|
}
|
|
|
|
)}
|
2024-01-30 08:55:15 +00:00
|
|
|
onMouseEnter={() => updateActiveBlock(block)}
|
|
|
|
onMouseLeave={() => updateActiveBlock(null)}
|
|
|
|
>
|
|
|
|
{!isBlockVisibleOnChart && <ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />}
|
|
|
|
<ChartDraggable
|
|
|
|
block={block}
|
|
|
|
blockToRender={blockToRender}
|
|
|
|
handleBlock={(...args) => handleChartBlockPosition(block, ...args)}
|
|
|
|
enableBlockLeftResize={enableBlockLeftResize}
|
|
|
|
enableBlockRightResize={enableBlockRightResize}
|
|
|
|
enableBlockMove={enableBlockMove}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
})}
|
2023-08-11 10:29:13 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|