@josmangarsal/pragmatic-scheduler
Version:
React resource scheduler
193 lines (192 loc) • 12.3 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimelineView = void 0;
var jsx_runtime_1 = require("@emotion/react/jsx-runtime");
var react_1 = require("react");
var Scheduler_1 = require("../components/Scheduler");
var HeaderRow_1 = require("../components/HeaderRow");
var material_1 = require("@mui/material");
var ResourceCell_1 = require("../layout/ResourceCell");
var ResourceHeader_1 = require("../layout/ResourceHeader");
var GridCell_1 = require("../layout/GridCell");
var react_grid_layout_1 = __importDefault(require("react-grid-layout"));
var EventTile_1 = require("../components/EventTile");
var UnassignedHeader_1 = require("../components/UnassignedHeader");
var useCalcEventPosition_1 = require("../hooks/useCalcEventPosition");
var useLayoutToCalEvent_1 = require("../hooks/useLayoutToCalEvent");
var useCalcGridPositions_1 = require("../hooks/useCalcGridPositions");
var date_fns_1 = require("date-fns");
var datePositionHelper_1 = require("../helpers/datePositionHelper");
var TimelineView = function () {
var _a = (0, react_1.useContext)(Scheduler_1.SchedulerContext), resources = _a.resources, events = _a.events, days = _a.days, config = _a.config, activeDate = _a.activeDate, _b = _a.calendarBounds, totalDivisions = _b.totalDivisions, start = _b.start, end = _b.end, onEventChange = _a.onEventChange;
var ref = (0, react_1.useRef)(null);
var calcEventPosition = (0, useCalcEventPosition_1.useCalcEventPosition)();
var layoutToCalEvent = (0, useLayoutToCalEvent_1.useLayoutToCalEvent)();
var gridLayouts = (0, useCalcGridPositions_1.useCalcGridPositions)();
var _c = __read((0, react_1.useState)(false), 2), isDraggingOver = _c[0], setIsDraggingOver = _c[1];
var _d = __read((0, react_1.useState)(), 2), dragCalEvent = _d[0], setDragCalEvent = _d[1];
var _e = __read((0, react_1.useState)({ i: 'droppedItem', w: 4, h: 1, x: 0, y: 0 }), 2), droppingItem = _e[0], setDroppingItem = _e[1];
var _f = __read((0, react_1.useState)(gridLayouts), 2), layouts = _f[0], setLayouts = _f[1];
var updateLayout = (0, react_1.useCallback)(function (layout) {
var gridIds = gridLayouts.map(function (l) { return l.i; });
var eventLayouts = layout.filter(function (l) { return !gridIds.includes(l.i); });
setLayouts(__spreadArray(__spreadArray([], __read(eventLayouts), false), __read(gridLayouts), false));
}, [gridLayouts]);
var prevActiveDate = (0, react_1.useRef)();
var prevStartDate = (0, react_1.useRef)();
var prevEndDate = (0, react_1.useRef)();
(0, react_1.useEffect)(function () {
var _a, _b, _c, _d, _e, _f, _g;
// Scroll to start on expand end date
if (prevStartDate.current && ((_a = prevStartDate.current) === null || _a === void 0 ? void 0 : _a.getTime()) !== start.getTime()) {
prevStartDate.current = start;
(_b = ref.current) === null || _b === void 0 ? void 0 : _b.scrollTo({
left: 0,
behavior: 'smooth',
});
return;
}
// Scroll to end on expand end date
if (prevEndDate.current && ((_c = prevEndDate.current) === null || _c === void 0 ? void 0 : _c.getTime()) !== end.getTime()) {
prevEndDate.current = end;
(_d = ref.current) === null || _d === void 0 ? void 0 : _d.scrollTo({
left: ref.current.scrollWidth,
behavior: 'smooth',
});
return;
}
setTimeout(function () {
prevStartDate.current = start;
prevEndDate.current = end;
}, 100);
// Don't scroll if activeDate has not changed
if (((_e = prevActiveDate.current) === null || _e === void 0 ? void 0 : _e.getTime()) === activeDate.getTime())
return;
prevActiveDate.current = activeDate;
if ((0, date_fns_1.isBefore)(start, activeDate) && (0, date_fns_1.isBefore)(activeDate, end)) {
// scroll to activeDate, that must be inside the current date interval
(_f = ref.current) === null || _f === void 0 ? void 0 : _f.scrollTo({
left: (0, datePositionHelper_1.dateToPosition)(activeDate, start, end, ref.current.scrollWidth),
behavior: 'smooth',
});
}
else {
// scroll to the current date (there is 1 day in the past)
(_g = ref.current) === null || _g === void 0 ? void 0 : _g.scrollTo({
left: ref.current.scrollWidth * (1 / (config.daysToDisplay + 1)),
behavior: 'smooth',
});
}
}, [activeDate, config.daysToDisplay, end, start]);
(0, react_1.useEffect)(function () {
var el = ref.current;
if (el) {
var onWheel_1 = function (e) {
if (e.deltaY === 0)
return;
if (!(el.scrollLeft === 0 && e.deltaY < 0) &&
!(el.scrollWidth - el.clientWidth - Math.round(el.scrollLeft) === 0 && e.deltaY > 0)) {
e.preventDefault();
}
el.scrollLeft += e.deltaY * 0.25;
};
el.addEventListener('wheel', onWheel_1);
return function () { return el.removeEventListener('wheel', onWheel_1); };
}
}, []);
var cols = (0, react_1.useMemo)(function () {
return totalDivisions * config.divisionParts;
}, [config.divisionParts, totalDivisions]);
var handleDrop = (0, react_1.useCallback)(function (_layout, layoutItem) {
if (dragCalEvent && layoutItem) {
var updatedEvent = layoutToCalEvent(layoutItem);
onEventChange === null || onEventChange === void 0 ? void 0 : onEventChange(updatedEvent);
setIsDraggingOver(false);
}
}, [dragCalEvent, layoutToCalEvent, onEventChange]);
var handleDropDragOver = (0, react_1.useCallback)(function () {
setIsDraggingOver(true);
return undefined;
}, [setIsDraggingOver]);
var handleUnassignedDragStart = (0, react_1.useCallback)(function (event) {
setDragCalEvent(event);
var layout = calcEventPosition(event);
setDroppingItem(layout);
}, [calcEventPosition]);
var handleDragResizeStop = (0, react_1.useCallback)(function (layout, _oldItem, newItem) {
var updatedEvent = layoutToCalEvent(newItem);
onEventChange === null || onEventChange === void 0 ? void 0 : onEventChange(updatedEvent);
// be sure to unset this so that the handleLayoutChange updates the layout
setIsDraggingOver(false);
setTimeout(function () {
// note this is required as the handleLayoutChange is not always triggered
// see: https://github.com/react-grid-layout/react-grid-layout/issues/1606
// the setTimeout is a hack as sometime it ges into a loop depending on how quickly the event is dropped
updateLayout(layout);
});
}, [layoutToCalEvent, onEventChange, updateLayout]);
var handleLayoutChange = (0, react_1.useCallback)(function (layout) {
// note we have to check if we are dragging over as the handleLayoutChange can remove the droppingItem
// which causes the handleDrop be called with an undefined layoutItem, and the "pink box" is not shown
if (!isDraggingOver) {
updateLayout(layout);
}
}, [isDraggingOver, updateLayout]);
return ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [config.unAssignedRows ? (0, jsx_runtime_1.jsx)(UnassignedHeader_1.UnassignedHeader, {}) : null, (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ display: "flex" }, { children: [(0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ marginTop: config.unAssignedRows ? "".concat(config.rowHeight * 2, "px") : 0, maxWidth: config.resourceColumnWidth, minWidth: config.resourceColumnWidth }, { children: [(0, jsx_runtime_1.jsx)(ResourceHeader_1.ResourceHeader, {}), resources.map(function (resource) { return ((0, jsx_runtime_1.jsx)(ResourceCell_1.ResourceCell, { resource: resource }, resource.id)); })] })), (0, jsx_runtime_1.jsxs)(material_1.Box, __assign({ position: "relative", flex: 1, overflow: "auto", ref: ref }, { children: [config.unAssignedRows ? (0, jsx_runtime_1.jsx)(HeaderRow_1.UnAssignedEvents, { onDragStart: handleUnassignedDragStart }) : null, (0, jsx_runtime_1.jsx)(HeaderRow_1.HeaderRow, { days: days }), (0, jsx_runtime_1.jsxs)(react_grid_layout_1.default, __assign({ className: "layout", margin: [0, 0], compactType: null, allowOverlap: true, cols: cols, rowHeight: config.rowHeight, width: (cols * config.divisionWidth) / config.divisionParts, isBounded: true, isDroppable: true, onDrop: handleDrop, onDropDragOver: handleDropDragOver, droppingItem: droppingItem, onDragStop: handleDragResizeStop, onResizeStop: handleDragResizeStop, layout: layouts, onLayoutChange: handleLayoutChange, draggableCancel: ".not-draggable" }, { children: [gridLayouts.map(function (layout) {
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(material_1.Box, __assign({ width: config.divisionWidth, height: config.rowHeight * layout.h - 2 }, { children: (0, jsx_runtime_1.jsx)(GridCell_1.GridCell, { layout: layout }) })) }, layout.i));
}), events
.filter(function (e) { return e.resourceId; })
.sort(function (a, b) { return (a.allowOverlap ? 0 : 1) - (b.allowOverlap ? 0 : 1); })
.map(function (event) {
var dataGridProps = calcEventPosition(event);
return ((0, jsx_runtime_1.jsx)("div", __assign({ "data-grid": dataGridProps }, { children: (0, jsx_runtime_1.jsx)(EventTile_1.EventTile, { event: event, infoFlowData: {
scrollRef: ref.current,
dataGridProps: dataGridProps,
config: config,
}, overflowData: {
leftOverflow: dataGridProps.leftOverflow,
middleOverflow: dataGridProps.middleOverflow,
rightOverflow: dataGridProps.rightOverflow,
} }, event.id) }), event.id));
})] }))] }))] }))] }));
};
exports.TimelineView = TimelineView;