refactor: gantt sidebar

This commit is contained in:
Aaryan Khandelwal 2024-02-05 14:55:58 +05:30
parent 4943eb397e
commit 38f6c03298
9 changed files with 122 additions and 123 deletions

View File

@ -1,4 +1,5 @@
import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
import { FC } from "react";
// hooks
import { useIssueDetail } from "hooks/store";
import { useChart } from "../hooks";
@ -20,7 +21,7 @@ export type GanttChartBlocksProps = {
showAllBlocks: boolean;
};
export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
export const GanttChartBlocksList: FC<GanttChartBlocksProps> = observer((props) => {
const {
itemsContainerWidth,
blocks,
@ -31,12 +32,10 @@ export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
enableBlockMove,
showAllBlocks,
} = props;
// refs
const blocksContainerRef = useRef<HTMLDivElement>(null);
// store hooks
const { peekIssue } = useIssueDetail();
// chart hook
const { activeBlock, dispatch, scrollTop, updateScrollTop } = useChart();
const { activeBlock, dispatch, updateScrollTop } = useChart();
// update the active block on hover
const updateActiveBlock = (block: IGanttBlock | null) => {
@ -87,54 +86,44 @@ export const GanttChartBlocksList: FC<GanttChartBlocksProps> = (props) => {
sidebarScrollContainer.scrollTop = e.currentTarget.scrollTop;
};
useEffect(() => {
const blocksContainer = blocksContainerRef.current;
if (!blocksContainer) return;
blocksContainer.scrollTop = scrollTop;
}, [scrollTop]);
return (
<div
ref={blocksContainerRef}
className="relative z-[5] mt-[72px] h-full overflow-hidden overflow-y-auto"
style={{ width: `${itemsContainerWidth}px` }}
onScroll={handleBlocksScroll}
>
{blocks &&
blocks.length > 0 &&
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;
{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;
const isBlockVisibleOnChart = block.start_date && block.target_date;
return (
<div
key={`block-${block.id}`}
className={cn("relative 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,
})}
onMouseEnter={() => updateActiveBlock(block)}
onMouseLeave={() => updateActiveBlock(null)}
>
{isBlockVisibleOnChart ? (
<ChartDraggable
block={block}
blockToRender={blockToRender}
handleBlock={(...args) => handleChartBlockPosition(block, ...args)}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
/>
) : (
<ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />
)}
</div>
);
})}
return (
<div
key={`block-${block.id}`}
className={cn("relative 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,
})}
onMouseEnter={() => updateActiveBlock(block)}
onMouseLeave={() => updateActiveBlock(null)}
>
{isBlockVisibleOnChart ? (
<ChartDraggable
block={block}
blockToRender={blockToRender}
handleBlock={(...args) => handleChartBlockPosition(block, ...args)}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
/>
) : (
<ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />
)}
</div>
);
})}
</div>
);
};
});

View File

@ -1,9 +1,9 @@
import { useRef } from "react";
// components
import {
BiWeekChartView,
DayChartView,
GanttChartBlocksList,
GanttChartSidebar,
HourChartView,
IBlockUpdateData,
IGanttBlock,
@ -51,16 +51,14 @@ export const GanttChartMainContent: React.FC<Props> = (props) => {
title,
updateCurrentViewRenderPayload,
} = props;
// refs
const sidebarRef = useRef<HTMLDivElement>(null);
// chart hook
const { currentView, currentViewData, updateScrollLeft, updateScrollTop } = useChart();
// handling scroll functionality
const onScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => {
const { clientWidth: clientVisibleWidth, scrollLeft: currentLeftScrollPosition, scrollWidth } = e.currentTarget;
updateScrollLeft(currentLeftScrollPosition);
updateScrollTop(e.currentTarget.scrollTop);
const approxRangeLeft = scrollWidth >= clientVisibleWidth + 1000 ? 1000 : scrollWidth - clientVisibleWidth;
const approxRangeRight = scrollWidth - (approxRangeLeft + clientVisibleWidth);
@ -69,8 +67,6 @@ export const GanttChartMainContent: React.FC<Props> = (props) => {
if (currentLeftScrollPosition <= approxRangeLeft) updateCurrentViewRenderPayload("left", currentView);
};
const onSidebarScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => updateScrollTop(e.currentTarget.scrollTop);
const CHART_VIEW_COMPONENTS: {
[key in TGanttViews]: React.FC;
} = {
@ -82,58 +78,45 @@ export const GanttChartMainContent: React.FC<Props> = (props) => {
quarter: QuarterChartView,
year: YearChartView,
};
if (!currentView) return null;
const ActiveChartView = CHART_VIEW_COMPONENTS[currentView];
return (
<div
// DO NOT REMOVE THE ID
id="gantt-container"
className={cn("relative flex h-full w-full flex-1 overflow-hidden border-t border-custom-border-200", {
className={cn("relative h-full w-full flex flex-1 overflow-hidden border-t border-custom-border-200", {
"mb-8": bottomSpacing,
})}
>
<GanttChartSidebar
blocks={blocks}
blockUpdateHandler={blockUpdateHandler}
enableReorder={enableReorder}
sidebarToRender={sidebarToRender}
title={title}
/>
<div
// DO NOT REMOVE THE ID
id="gantt-sidebar"
className="flex h-full w-1/4 flex-col border-r border-custom-border-200"
id="scroll-container"
className="relative h-full w-full flex flex-col flex-1 overflow-hidden overflow-x-auto horizontal-scroll-enable"
onScroll={onScroll}
>
<div className="box-border flex h-[60px] flex-shrink-0 items-end justify-between gap-2 border-b border-custom-border-200 pb-2 pl-10 pr-4 text-sm font-medium text-custom-text-300">
<h6>{title}</h6>
<h6>Duration</h6>
</div>
<div
id="gantt-sidebar-scroll-container"
className="max-h-full mt-[12px] overflow-y-auto pl-2.5"
onScroll={onSidebarScroll}
ref={sidebarRef}
>
{sidebarToRender && sidebarToRender({ title, blockUpdateHandler, blocks, enableReorder })}
</div>
<ActiveChartView />
{currentViewData && (
<GanttChartBlocksList
itemsContainerWidth={itemsContainerWidth}
blocks={chartBlocks}
blockToRender={blockToRender}
blockUpdateHandler={blockUpdateHandler}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
showAllBlocks={showAllBlocks}
/>
)}
</div>
{currentView && (
<div
// DO NOT REMOVE THE ID
id="scroll-container"
className="relative flex h-full w-full flex-1 flex-col overflow-hidden overflow-x-auto horizontal-scroll-enable"
onScroll={onScroll}
>
<ActiveChartView />
{/* blocks */}
{currentViewData && (
<GanttChartBlocksList
itemsContainerWidth={itemsContainerWidth}
blocks={chartBlocks}
blockToRender={blockToRender}
blockUpdateHandler={blockUpdateHandler}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
showAllBlocks={showAllBlocks}
/>
)}
</div>
)}
</div>
);
};

View File

@ -14,7 +14,7 @@ export const MonthChartView: FC<any> = () => {
return (
<>
<div className="absolute flex h-full flex-grow divide-x divide-custom-border-100/50">
<div className="absolute h-full flex flex-grow divide-x divide-custom-border-100/50">
{monthBlocks?.map((block, rootIndex) => (
<div key={`month-${block?.month}-${block?.year}`} className="relative flex flex-col">
<div className="h-[60px] w-full">

View File

@ -1,4 +1,3 @@
import { useRouter } from "next/router";
import { DragDropContext, Draggable, DropResult, Droppable } from "@hello-pangea/dnd";
import { MoreVertical } from "lucide-react";
// hooks
@ -20,12 +19,8 @@ type Props = {
};
export const CycleGanttSidebar: React.FC<Props> = (props) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { title, blockUpdateHandler, blocks, enableReorder } = props;
const router = useRouter();
const { cycleId } = router.query;
const { blockUpdateHandler, blocks, enableReorder } = props;
// chart hook
const { activeBlock, dispatch } = useChart();
// update the active block on hover
@ -85,7 +80,6 @@ export const CycleGanttSidebar: React.FC<Props> = (props) => {
<Droppable droppableId="gantt-sidebar">
{(droppableProvided) => (
<div
id={`gantt-sidebar-${cycleId}`}
className="mt-3 max-h-full overflow-y-auto pl-2.5"
ref={droppableProvided.innerRef}
{...droppableProvided.droppableProps}

View File

@ -1,4 +1,5 @@
export * from "./cycle-sidebar";
export * from "./module-sidebar";
export * from "./sidebar";
export * from "./project-view-sidebar";
export * from "./cycles";
export * from "./issues";
export * from "./modules";
export * from "./project-views";
export * from "./root";

View File

@ -1,3 +1,4 @@
import { observer } from "mobx-react";
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
import { MoreVertical } from "lucide-react";
// hooks
@ -30,7 +31,7 @@ type Props = {
showAllBlocks?: boolean;
};
export const IssueGanttSidebar: React.FC<Props> = (props) => {
export const IssueGanttSidebar: React.FC<Props> = observer((props) => {
const {
blockUpdateHandler,
blocks,
@ -101,7 +102,7 @@ export const IssueGanttSidebar: React.FC<Props> = (props) => {
<DragDropContext onDragEnd={handleOrderChange}>
<Droppable droppableId="gantt-sidebar">
{(droppableProvided) => (
<div id={`gantt-sidebar-${viewId}`} ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}>
<div ref={droppableProvided.innerRef} {...droppableProvided.droppableProps}>
<>
{blocks ? (
blocks.map((block, index) => {
@ -189,4 +190,4 @@ export const IssueGanttSidebar: React.FC<Props> = (props) => {
</Droppable>
</DragDropContext>
);
};
});

View File

@ -1,4 +1,3 @@
import { useRouter } from "next/router";
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
import { MoreVertical } from "lucide-react";
// hooks
@ -20,12 +19,8 @@ type Props = {
};
export const ModuleGanttSidebar: React.FC<Props> = (props) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { title, blockUpdateHandler, blocks, enableReorder } = props;
const router = useRouter();
const { cycleId } = router.query;
const { blockUpdateHandler, blocks, enableReorder } = props;
// chart hook
const { activeBlock, dispatch } = useChart();
// update the active block on hover
@ -85,7 +80,6 @@ export const ModuleGanttSidebar: React.FC<Props> = (props) => {
<Droppable droppableId="gantt-sidebar">
{(droppableProvided) => (
<div
id={`gantt-sidebar-${cycleId}`}
className="mt-3 max-h-full overflow-y-auto pl-2.5"
ref={droppableProvided.innerRef}
{...droppableProvided.droppableProps}

View File

@ -1,4 +1,3 @@
import { useRouter } from "next/router";
import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd";
import { MoreVertical } from "lucide-react";
// hooks
@ -21,12 +20,8 @@ type Props = {
};
export const ProjectViewGanttSidebar: React.FC<Props> = (props) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { title, blockUpdateHandler, blocks, enableReorder } = props;
const router = useRouter();
const { cycleId } = router.query;
const { blockUpdateHandler, blocks, enableReorder } = props;
// chart hook
const { activeBlock, dispatch } = useChart();
// update the active block on hover
@ -86,7 +81,6 @@ export const ProjectViewGanttSidebar: React.FC<Props> = (props) => {
<Droppable droppableId="gantt-sidebar">
{(droppableProvided) => (
<div
id={`gantt-sidebar-${cycleId}`}
className="mt-3 max-h-full overflow-y-auto pl-2.5"
ref={droppableProvided.innerRef}
{...droppableProvided.droppableProps}

View File

@ -0,0 +1,43 @@
import { useRef } from "react";
// components
import { IBlockUpdateData, IGanttBlock, useChart } from "components/gantt-chart";
type Props = {
blocks: IGanttBlock[] | null;
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
enableReorder: boolean;
sidebarToRender: (props: any) => React.ReactNode;
title: string;
};
export const GanttChartSidebar: React.FC<Props> = (props) => {
const { blocks, blockUpdateHandler, enableReorder, sidebarToRender, title } = props;
// refs
const sidebarRef = useRef<HTMLDivElement>(null);
// chart hook
const { updateScrollTop } = useChart();
const onSidebarScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => updateScrollTop(e.currentTarget.scrollTop);
return (
<div
// DO NOT REMOVE THE ID
id="gantt-sidebar"
className="flex h-full w-1/4 flex-col border-r border-custom-border-200"
>
<div className="box-border h-[60px] flex-shrink-0 flex items-end justify-between gap-2 border-b border-custom-border-200 pb-2 pl-10 pr-4 text-sm font-medium text-custom-text-300">
<h6>{title}</h6>
<h6>Duration</h6>
</div>
<div
id="gantt-sidebar-scroll-container"
className="max-h-full mt-[12px] pl-2.5 overflow-hidden overflow-y-auto"
onScroll={onSidebarScroll}
ref={sidebarRef}
>
{sidebarToRender && sidebarToRender({ title, blockUpdateHandler, blocks, enableReorder })}
</div>
</div>
);
};