@parkassist/pa-ui-library
Version:
INX Platform elements
200 lines • 7.09 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useEffect, useRef, useState } from "react";
import { checkIfClicked, checkIsInRange, createRanges, formatRanges, getNoOverlappingRangesAndFinalEnd, getOptions, prepareRange, setStartEndTimes } from "./WeekHoursPickerUtils";
import { DayCell, HourCell, PickerCell, PickerRow } from "./styled";
import { DAYS, HOURS } from "./constants";
import Palette from "../../constants/Palette";
function WeekHoursPicker({
halfHourInterval,
selectionColor = "rgba(197, 216, 0, .4)",
hoverColor = "rgba(197, 216, 0, .3)",
cellHeight = 30,
width = "100%",
onChange,
value,
days = DAYS
}) {
const interval = halfHourInterval ? 30 : 15;
const options = getOptions(interval);
const headingHeight = 30;
const [selectedRanges, setSelectedRanges] = useState([]);
const [hoveredRange, setHoveredRange] = useState([]);
const [clickedElement, setClickedElement] = useState(null);
const pickerRef = useRef();
const [isDragging, setIsDragging] = useState(false);
useEffect(() => {
const ranges = createRanges(value, interval);
setSelectedRanges(ranges);
}, [value, interval]);
useEffect(() => {
const onClickOutside = event => {
if (!pickerRef.current.contains(event.target)) {
clearFirstClick();
}
};
document.addEventListener("click", onClickOutside);
return () => {
document.removeEventListener("click", onClickOutside);
};
}, []);
const clearFirstClick = () => {
setIsDragging(false);
setHoveredRange([]);
setClickedElement(null);
};
const createNewRanges = (el, day) => {
const selectedElement = Object.assign({}, clickedElement);
const updatedElement = setStartEndTimes(el, selectedElement);
const {
notOverlappingRanges,
finalTime
} = getNoOverlappingRangesAndFinalEnd(selectedRanges.filter(range => range.day === day), updatedElement, interval);
const range = prepareRange(updatedElement, finalTime, day);
return {
range,
notOverlappingRanges
};
};
const onMouseHover = (el, day) => {
if (day !== clickedElement.day) {
const firstDay = day < clickedElement.day ? day : clickedElement.day;
const secondDay = day > clickedElement.day ? day : clickedElement.day;
let result = [];
for (let currentDay = firstDay; currentDay <= secondDay; currentDay++) {
const {
range,
notOverlappingRanges
} = createNewRanges(el, currentDay);
result = [...result, range, ...notOverlappingRanges];
}
const resFromOtherRows = selectedRanges.filter(range => range.day < firstDay || range.day > secondDay);
return [...result, ...resFromOtherRows];
}
const {
range,
notOverlappingRanges
} = createNewRanges(el, day);
const resFromOtherRows = selectedRanges.filter(range => range.day !== day);
return [range, ...notOverlappingRanges, ...resFromOtherRows];
};
const handleChange = newRanges => {
const ranges = formatRanges(newRanges, interval);
onChange(ranges);
};
const handleMouseOver = (el, day) => {
setHoveredRange(onMouseHover(el, day));
};
const handleDelete = (el, dayNum) => {
const index = selectedRanges.findIndex(range => range.day === dayNum && el.time >= range.start.time && el.time <= range.end.time);
const updatedRanges = [...selectedRanges];
updatedRanges.splice(index, 1);
handleChange(updatedRanges);
};
const handleMouseDown = (el, day) => {
setIsDragging(true);
const range = {
day,
start: el,
end: el
};
setClickedElement(range);
};
const handleMouseUp = (el, day) => {
if (!isDragging) return;
setIsDragging(false);
setHoveredRange([]);
setClickedElement(null);
const newRanges = hoveredRange.length > 0 ? [...hoveredRange] : onMouseHover(el, day);
handleChange(newRanges);
};
const checkSelection = (element, dayNum, range, hover = false) => {
const completeElement = Object.assign(Object.assign({}, element), {
day: dayNum
});
if (checkIfClicked(clickedElement, completeElement)) return !hover;
const index = range.findIndex(selected => {
return checkIsInRange(selected, completeElement);
});
return index !== -1;
};
const getColor = (element, dayNum) => {
if (checkSelection(element, dayNum, selectedRanges)) return selectionColor;
if (checkSelection(element, dayNum, hoveredRange, true)) return hoverColor;
return "";
};
const getBorderStyles = (selected, index) => {
const daysInterval = 60 / interval;
const thickBorder = `2px solid ${Palette.BAY_OUT}`;
const thinBorder = selected ? "1px solid rgba(200,200,200,0.25)" : "1px solid rgba(243,243,243,0.85)";
const borderRight = index === options.length - 1 ? thickBorder : thinBorder;
return {
borderLeft: index % daysInterval === 0 ? thickBorder : thinBorder,
borderRight: ((index + 1) % daysInterval !== 0 || index === 0 || index === options.length - 1) && borderRight
};
};
const buildRangePicker = () => {
return DAYS.map((day, dayNum) => {
return _jsx(PickerRow, {
"data-testid": "week-hours-picker-" + day.toLowerCase(),
dayNum: dayNum,
children: options.map((option, index) => {
const selected = checkSelection(option, dayNum, selectedRanges);
const selectedOrHovered = selected || checkSelection(option, dayNum, hoveredRange, true);
return _jsx(PickerCell, {
"data-testid": "day-hours-picker-" + option.label,
height: cellHeight,
style: Object.assign({
background: getColor(option, dayNum),
userSelect: 'none',
cursor: 'pointer'
}, getBorderStyles(selectedOrHovered, index)),
onMouseOver: () => isDragging && handleMouseOver(option, dayNum),
onMouseDown: () => {
if (selected) handleDelete(option, dayNum);else handleMouseDown(option, dayNum);
},
onMouseUp: () => handleMouseUp(option, dayNum),
children: "\u00A0"
}, option.label);
})
}, day);
});
};
return _jsxs("div", {
style: {
display: "flex"
},
children: [_jsxs("div", {
children: [_jsx("div", {
style: {
height: `${headingHeight}px`
},
children: "\u00A0"
}), DAYS.map((day, index) => {
return _jsx(DayCell, {
index: index,
height: cellHeight,
children: days[index]
}, day);
})]
}), _jsxs("div", {
style: {
width: width
},
children: [_jsx("div", {
style: {
display: "flex"
},
children: HOURS.map(hour => {
return _jsx(HourCell, {
height: headingHeight,
children: hour
}, hour);
})
}), _jsx("div", {
ref: pickerRef,
children: buildRangePicker()
})]
})]
});
}
export default WeekHoursPicker;