diff --git a/example/src/components/gantt-table.tsx b/example/src/components/gantt-table.tsx index a38ed05..5687115 100644 --- a/example/src/components/gantt-table.tsx +++ b/example/src/components/gantt-table.tsx @@ -26,38 +26,6 @@ export const GanttTableExample: React.SFC = props => { options.columnWidth = 250; } - const [tasks, setTasks] = React.useState(props.tasks); - const onTaskDateChange = async (task: Task) => { - if (props.onDateChange) { - try { - await props.onDateChange(task); - } catch (e) { - throw e; - } - setTasks(tasks.map(t => (t.id === task.id ? task : t))); - } - }; - - const onTaskProgressChange = async (task: Task) => { - if (props.onProgressChange) { - try { - await props.onProgressChange(task); - } catch (e) { - setTasks(props.tasks.slice()); - throw e; - } - - setTasks(tasks.map(t => (t.id === task.id ? task : t))); - } - }; - - const onTaskItemDelete = async (task: Task) => { - if (props.onTaskDelete) { - await props.onTaskDelete(task); - setTasks(tasks.filter(t => t.id !== task.id)); - } - }; - return (
= props => { To
- {tasks.map(t => { + {props.tasks.map(t => { return (
= props => { })}
- +
); diff --git a/src/components/Bar/bar.tsx b/src/components/Bar/bar.tsx index 7f2eb7f..e32c698 100644 --- a/src/components/Bar/bar.tsx +++ b/src/components/Bar/bar.tsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; -import { Task } from "../../types/public-types"; import { BarProgressHandle } from "./bar-progress-handle"; import { BarDateHandle } from "./bar-date-handle"; import { BarDisplay } from "./bar-display"; @@ -14,7 +13,6 @@ import { GanttContentMoveAction } from "../Gantt/gantt-content"; export type BarProps = { task: BarTask; arrowIndent: number; - onDoubleClick?: (task: Task) => any; isProgressChangeable: boolean; isDateChangeable: boolean; isDelete: boolean; @@ -28,7 +26,6 @@ export type BarProps = { export const Bar: React.FC = ({ task, arrowIndent, - onDoubleClick, isProgressChangeable, isDateChangeable, onEventStart, @@ -46,8 +43,8 @@ export const Bar: React.FC = ({ return ( { - !!onDoubleClick && onDoubleClick(task); + onDoubleClick={e => { + onEventStart(e, "dblclick", task); }} tabIndex={0} onKeyDown={e => { diff --git a/src/components/Gantt/gantt-content.tsx b/src/components/Gantt/gantt-content.tsx index 73c7a8e..2eaed0e 100644 --- a/src/components/Gantt/gantt-content.tsx +++ b/src/components/Gantt/gantt-content.tsx @@ -15,6 +15,7 @@ export type GanttContentMoveAction = | "mouseenter" | "mouseleave" | "delete" + | "dblclick" | BarMoveAction; export type BarEvent = { selectedTask?: BarTask; @@ -44,14 +45,15 @@ export type GanttContentProps = { fontSize: string, fontFamily: string ) => JSX.Element; + onTasksDateChange: (tasks: Task[]) => void; } & EventOption; export const GanttContent: React.FC = ({ tasks, + dates, rowHeight, barCornerRadius, columnWidth, - dates, barFill, barProgressColor, barProgressSelectedColor, @@ -59,12 +61,13 @@ export const GanttContent: React.FC = ({ barBackgroundSelectedColor, headerHeight, handleWidth, - arrowColor, timeStep, + svg, + arrowColor, + arrowIndent, fontFamily, fontSize, - arrowIndent, - svg, + onTasksDateChange, onDateChange, onProgressChange, onDoubleClick, @@ -79,6 +82,7 @@ export const GanttContent: React.FC = ({ const [xStep, setXStep] = useState(0); const [initEventX1Delta, setInitEventX1Delta] = useState(0); const [isMoving, setIsMoving] = useState(false); + // create xStep useEffect(() => { const dateDelta = @@ -94,21 +98,13 @@ export const GanttContent: React.FC = ({ // generate tasks useEffect(() => { - const dateDelta = - dates[1].getTime() - - dates[0].getTime() - - dates[1].getTimezoneOffset() * 60 * 1000 + - dates[0].getTimezoneOffset() * 60 * 1000; - const taskHeight = (rowHeight * barFill) / 100; - setBarTasks( convertToBarTasks( tasks, dates, - dateDelta, columnWidth, rowHeight, - taskHeight, + barFill, headerHeight, barCornerRadius, handleWidth, @@ -136,14 +132,20 @@ export const GanttContent: React.FC = ({ /** * Method is Start point of task change */ - const handleBarEventStart = ( + const handleBarEventStart = async ( event: React.MouseEvent | React.KeyboardEvent, action: GanttContentMoveAction, selectedTask: BarTask ) => { if (isKeyboardEvent(event)) { if (action === "delete") { - setBarTasks(barTasks.filter(t => t.id !== barEvent.selectedTask?.id)); + if (onTaskDelete) { + await onTaskDelete(selectedTask); + const newTasks = barTasks.filter( + t => t.id !== barEvent.selectedTask?.id + ); + onTasksDateChange(newTasks); + } } } else if (action === "mouseenter") { if (!barEvent.action) { @@ -161,6 +163,8 @@ export const GanttContent: React.FC = ({ ); setInitEventX1Delta(cursor.x - selectedTask.x1); setBarEvent({ action, selectedTask }); + } else if (action === "dblclick") { + !!onDoubleClick && onDoubleClick(selectedTask); } else { setBarEvent({ action, @@ -217,9 +221,13 @@ export const GanttContent: React.FC = ({ (action === "move" || action === "end" || action === "start") && onDateChange ) { - onDateChange(changedTask); + await onDateChange(changedTask); + const newTasks = barTasks.map(t => + t.id === changedTask.id ? changedTask : t + ); + onTasksDateChange(newTasks); } else if (onProgressChange) { - onProgressChange(changedTask); + await onProgressChange(changedTask); } svg.current.removeEventListener("mousemove", handleMouseMove); svg.current.removeEventListener("mouseup", handleMouseUp); @@ -275,7 +283,6 @@ export const GanttContent: React.FC = ({ task={task} arrowIndent={arrowIndent} isProgressChangeable={!!onProgressChange && !task.isDisabled} - onDoubleClick={onDoubleClick} isDateChangeable={!!onDateChange && !task.isDisabled} isDelete={!!onTaskDelete && !task.isDisabled} onEventStart={handleBarEventStart} diff --git a/src/components/Gantt/gantt.tsx b/src/components/Gantt/gantt.tsx index 9b065d7..9e3990c 100644 --- a/src/components/Gantt/gantt.tsx +++ b/src/components/Gantt/gantt.tsx @@ -1,5 +1,5 @@ -import React, { useRef } from "react"; -import { ViewMode, GanttProps } from "../../types/public-types"; +import React, { useRef, useState } from "react"; +import { ViewMode, GanttProps, Task } from "../../types/public-types"; import { Grid, GridProps } from "../Grid/grid"; import { Calendar, CalendarProps } from "../Calendar/calendar"; import { GanttContent, GanttContentProps } from "./gantt-content"; @@ -31,14 +31,19 @@ export const Gantt: React.SFC = ({ onTaskDelete, getTooltipContent, }) => { - const [startDate, endDate] = ganttDateRange(tasks, viewMode); - const dates = seedDates(startDate, endDate, viewMode); const svg = useRef(null); + const [ganttTasks, setGanttTasks] = useState(tasks); + const [startDate, endDate] = ganttDateRange(ganttTasks, viewMode); + const dates = seedDates(startDate, endDate, viewMode); + + const handleOnTasksChange = (tasks: Task[]) => { + setGanttTasks(tasks); + }; const gridProps: GridProps = { columnWidth, gridWidth: dates.length * columnWidth, - tasks, + tasks: ganttTasks, rowHeight, headerHeight, dates, @@ -54,7 +59,7 @@ export const Gantt: React.SFC = ({ fontSize, }; const barProps: GanttContentProps = { - tasks, + tasks: ganttTasks, rowHeight, barCornerRadius, columnWidth, @@ -66,12 +71,13 @@ export const Gantt: React.SFC = ({ barBackgroundSelectedColor, headerHeight, handleWidth, - timeStep, arrowColor, + timeStep, fontFamily, fontSize, arrowIndent, svg, + onTasksDateChange: handleOnTasksChange, onDateChange, onProgressChange, onDoubleClick, diff --git a/src/helpers/bar-helper.ts b/src/helpers/bar-helper.ts index e1bc2ee..125d4e7 100644 --- a/src/helpers/bar-helper.ts +++ b/src/helpers/bar-helper.ts @@ -4,10 +4,9 @@ import { BarTask } from "../types/bar-task"; export const convertToBarTasks = ( tasks: Task[], dates: Date[], - dateDelta: number, columnWidth: number, rowHeight: number, - taskHeight: number, + barFill: number, headerHeight: number, barCornerRadius: number, handleWidth: number, @@ -16,6 +15,13 @@ export const convertToBarTasks = ( barBackgroundColor: string, barBackgroundSelectedColor: string ) => { + const dateDelta = + dates[1].getTime() - + dates[0].getTime() - + dates[1].getTimezoneOffset() * 60 * 1000 + + dates[0].getTimezoneOffset() * 60 * 1000; + const taskHeight = (rowHeight * barFill) / 100; + let barTasks = tasks.map((t, i) => { return convertToBarTask( t, @@ -35,6 +41,7 @@ export const convertToBarTasks = ( ); }); + // set dependencies barTasks = barTasks.map((task, i) => { const dependencies = task.dependencies || []; for (let j = 0; j < dependencies.length; j++) { diff --git a/src/helpers/other-helper.ts b/src/helpers/other-helper.ts index 36d226e..2f27bf5 100644 --- a/src/helpers/other-helper.ts +++ b/src/helpers/other-helper.ts @@ -1,5 +1,12 @@ +import { BarTask } from "../types/bar-task"; +import { Task } from "../types/public-types"; + export function isKeyboardEvent( event: React.MouseEvent | React.KeyboardEvent ): event is React.KeyboardEvent { return (event as React.KeyboardEvent).key !== undefined; } + +export function isBarTask(task: Task | BarTask): task is BarTask { + return (task as BarTask).x1 !== undefined; +} diff --git a/src/types/public-types.ts b/src/types/public-types.ts index 27ac75e..424e133 100644 --- a/src/types/public-types.ts +++ b/src/types/public-types.ts @@ -30,7 +30,7 @@ export interface EventOption { * Time step value for date changes. */ timeStep?: number; - onDoubleClick?: (task: Task) => any; + onDoubleClick?: (task: Task) => void; onDateChange?: (task: Task) => void | Promise; onProgressChange?: (task: Task) => void | Promise; onTaskDelete?: (task: Task) => void | Promise;