@activecollab/components
Version:
ActiveCollab Components
250 lines (249 loc) • 8.87 kB
JavaScript
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