UNPKG

@parkassist/pa-ui-library

Version:
200 lines 7.09 kB
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;