UNPKG

@activecollab/components

Version:

ActiveCollab Components

250 lines (249 loc) • 8.87 kB
import React, { useCallback, useMemo, useState, useEffect } from "react"; import classNames from "classnames"; import moment from "moment"; import { StyledButton, StyledButtonGroup, StyledDiv, StyledMenu, StyledSpan, StyledControl } from "./Styles"; import { DatePicker } from "../../DatePicker"; import { ArrowRightIcon } from "../../Icons"; import ArrowLeftIcon from "../../Icons/collection/ArrowLeft"; /** * This component allow you to select date range. It accepts two parameters "from" and "to" as valid format * onChange and onBack and onForward it will return "from: Date" and "to: Date" as function arguments */ export const DateStepper = _ref => { let { step, formatCallback, onChange, from, to, onBack, onForward, minValue, maxValue, className, period = "week", datePickerClass, withDatePicker = true, defaultMonth = new Date(), popperClassName, position = "bottom" } = _ref; const [fromDate, setFromDate] = useState(moment(from)); const [toDate, setToDate] = useState(moment(to)); const [showDatePicker, setShowDatePicker] = useState(false); const [month, setMonth] = useState(defaultMonth); const getDatesByPeriod = useCallback(interval => { const date = fromDate ? fromDate : moment(); if (step === "daily") { date.add(interval, "days"); return [date, date.clone()]; } else if (step === "weekly") { date.add(interval, "weeks"); return [date.clone().startOf(period), date.clone().endOf(period)]; } else if (step === "monthly") { date.add(interval, "months"); return [date.clone().startOf("month"), date.clone().endOf("month")]; } else if (step === "quarterly") { date.add(interval, "quarters"); return [date.clone().startOf("quarter"), date.clone().endOf("quarter")]; } else if (step === "yearly") { date.add(interval, "years"); return [date.clone().startOf("year"), date.clone().endOf("year")]; } return [date, date]; }, [fromDate, period, step]); const getDateFormatted = useMemo(() => { if (formatCallback) { return formatCallback(fromDate.toDate(), toDate.toDate()); } const actualYear = moment().year(); const showWeekOrCustomDateFormat = (start, end) => { if (start.year() === actualYear && end.year() === actualYear) { return start.format("MMM DD") + " - " + end.format("MMM DD"); } else { return start.format("MMM DD YYYY") + " - " + end.format("MMM DD YYYY"); } }; if (step === "daily") { if (fromDate.year() === actualYear) { return fromDate.format("MMM DD"); } return fromDate.format("MMM DD YYYY"); } else if (step === "weekly") { const startDate = fromDate.clone().startOf(period); const endDate = startDate.clone().endOf(period); return showWeekOrCustomDateFormat(startDate, endDate); } else if (step === "monthly") { return fromDate.format("MMM YYYY"); } else if (step === "quarterly") { return "Q" + fromDate.quarter() + "/" + fromDate.format("YYYY"); } else if (step === "yearly") { return fromDate.format("YYYY"); } else if (step === "custom") { return showWeekOrCustomDateFormat(fromDate, toDate); } return ""; }, [fromDate, step, toDate, formatCallback, period]); const onChangeCallback = useCallback(amount => { const [newFrom, newTo] = getDatesByPeriod(amount); setFromDate(moment(newFrom)); setToDate(moment(newTo)); if (onChange) { onChange(newFrom.toDate(), newTo.toDate()); } }, [onChange, getDatesByPeriod]); const onDatePickerChange = useCallback(dates => { const fromDateTemp = dates == null ? void 0 : dates.from; const toDateTemp = dates == null ? void 0 : dates.to; setFromDate(moment(fromDateTemp)); setToDate(moment(toDateTemp)); if (onChange && fromDateTemp instanceof Date && toDateTemp instanceof Date) { onChange(fromDateTemp, toDateTemp); } }, [onChange, setFromDate, setToDate]); const isAfterMaxDate = useMemo(() => { return maxValue instanceof Date && moment(moment(maxValue).format("YYYY-MM-DD")).isSameOrBefore(toDate.format("YYYY-MM-DD")); }, [maxValue, toDate]); const isBeforeMinDate = useMemo(() => { return minValue instanceof Date && moment(moment(minValue).format("YYYY-MM-DD")).isSameOrAfter(toDate.format("YYYY-MM-DD")); }, [minValue, toDate]); useEffect(() => { if (isBeforeMinDate) { if (step === "daily") { setFromDate(moment(minValue)); setToDate(moment(minValue)); } } if (isAfterMaxDate) { if (step === "daily") { setFromDate(moment(maxValue)); setToDate(moment(maxValue)); } } }, [step, minValue, maxValue, isBeforeMinDate, isAfterMaxDate]); const onRightClickHandler = useCallback(() => { if (isAfterMaxDate) { return; } onChangeCallback(1); if (onForward) { onForward(fromDate.toDate(), toDate.toDate()); } }, [isAfterMaxDate, onChangeCallback, onForward, fromDate, toDate]); const onLeftClickHandler = useCallback(() => { if (isBeforeMinDate) { return; } onChangeCallback(-1); if (onBack) { onBack(fromDate.toDate(), toDate.toDate()); } }, [isBeforeMinDate, onChangeCallback, onBack, fromDate, toDate]); const renderLeftRightButtons = useMemo(() => { return step !== "custom"; }, [step]); const handleShow = useCallback(() => { setShowDatePicker(!showDatePicker); if (fromDate) { setMonth(fromDate.toDate()); } }, [setShowDatePicker, showDatePicker, fromDate]); const closeMenu = useCallback(() => { setShowDatePicker(false); }, []); const onMonthChange = useCallback(m => { setMonth(m); }, [setMonth]); useEffect(() => { setFromDate(moment(from)); setToDate(moment(to)); }, [from, to]); const dateStepperWidth = (fromDay, toDay, range) => { if (fromDay.year() !== moment().year() || toDay.year() !== moment().year()) { switch (range) { case "daily": case "monthly": return { minWidth: "122px" }; case "weekly": case "custom": return { minWidth: "232px" }; } } switch (range) { case "monthly": return { minWidth: "122px" }; case "weekly": case "custom": return { minWidth: "182px" }; } return { minWidth: "102px" }; }; const isDisabled = useCallback(day => { const dayFormat = moment(day).format("YYYY-MM-DD"); const isBefore = maxValue instanceof Date && moment(moment(maxValue).format("YYYY-MM-DD")).isBefore(dayFormat); const isAfter = minValue instanceof Date && moment(moment(minValue).format("YYYY-MM-DD")).isAfter(dayFormat); return isBefore || isAfter; }, [maxValue, minValue]); const modifiers = useMemo(() => { return { day_disabled: day => { return isDisabled(day); }, nonWorkingDay: day => { return isDisabled(day); } }; }, [isDisabled]); return /*#__PURE__*/React.createElement(StyledButtonGroup, { className: classNames("c-date-stepper", className) }, renderLeftRightButtons ? /*#__PURE__*/React.createElement(StyledControl, { type: "button", variant: "secondary", onClick: onLeftClickHandler, disabled: isBeforeMinDate }, /*#__PURE__*/React.createElement(ArrowLeftIcon, null)) : null, /*#__PURE__*/React.createElement(StyledDiv, { $isTargetable: step === "yearly" || !withDatePicker, $isRounded: step === "custom", style: dateStepperWidth(fromDate, toDate, step) }, withDatePicker ? /*#__PURE__*/React.createElement(StyledMenu, { target: /*#__PURE__*/React.createElement(StyledButton, { type: "button" }, /*#__PURE__*/React.createElement("span", null, getDateFormatted)), open: showDatePicker, onOpen: handleShow, onClose: closeMenu, popperClassName: popperClassName, position: position }, /*#__PURE__*/React.createElement(DatePicker, { month: month, selectionMode: step, className: datePickerClass, selectedDays: { from: fromDate.toDate(), to: toDate.toDate() }, onChange: onDatePickerChange, onMonthChange: onMonthChange, firstDayOfWeek: period === "week" ? 0 : 1, modifiers: modifiers, dateRequired: true, fixedWeeks: true })) : /*#__PURE__*/React.createElement(StyledSpan, null, getDateFormatted)), renderLeftRightButtons ? /*#__PURE__*/React.createElement(StyledControl, { type: "button", variant: "secondary", onClick: onRightClickHandler, disabled: isAfterMaxDate }, /*#__PURE__*/React.createElement(ArrowRightIcon, null)) : null); }; DateStepper.displayName = "DateStepper"; //# sourceMappingURL=DateStepper.js.map