@parkassist/pa-ui-library
Version:
INX Platform elements
335 lines (334 loc) • 11.7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useEffect, useState } from "react";
import dayjs from "dayjs";
import DayRangePicker from "./DateRangeCalendar";
import { Column, Row } from "../Layout/Flex";
import Modal from "../Modal";
import styled from "styled-components";
import "react-day-picker/lib/style.css";
import HourRangePicker, { getHourRangeMarks } from "./HourRangePicker";
import Palette from "../../constants/Palette";
import * as Icons from "../Icons";
import FontStyles from "../../constants/FontStyles";
import Helmet from "react-helmet";
import MaterialInput from "../MaterialInput";
import { enUS } from "date-fns/locale";
const SelectorWrapper = styled.div(() => ({
marginTop: 0
}));
const LabelWrapper = styled(Row)(() => ({
marginBottom: 1,
font: FontStyles.LABEL_FONT
}));
const FakeSelector = styled.div(({
width,
backgroundColor,
borderColor
}) => ({
width,
minWidth: 180,
display: "flex",
paddingLeft: 8,
alignItems: "center",
backgroundColor,
borderRadius: 3,
color: Palette.BLACK,
height: 32,
transition: "all 0.2s",
"&:hover": {
transform: "scale(1.02)"
}
}));
const formatHours = (hours, isEnd) => {
let formattedHours = "";
if (isEnd) hours -= 1;
if (hours < 10) formattedHours += "0";
if (isEnd) formattedHours += `${hours}:59:59`;else formattedHours += `${hours}:00:00`;
return formattedHours;
};
const formatHoursToNumber = (hours, isEnd) => {
if (!hours) {
if (isEnd) {
return 24;
}
return 0;
}
if (isEnd) {
return Number(hours.slice(0, 2)) + 1;
}
return Number(hours.slice(0, 2));
};
const getHourRange = hourRange => {
const [hourFromNumber, hourToNumber] = hourRange;
const hourFrom = hourFromNumber === 0 && hourToNumber === 24 ? null : formatHours(hourFromNumber, false);
const hourTo = hourFromNumber === 0 && hourToNumber === 24 ? null : formatHours(hourToNumber, true);
return {
hourFrom,
hourTo
};
};
export const formatToLocalTimezone = time => {
const timeWithNoTZ = (dayjs.isDayjs(time) ? time.format() : time).slice(0, 19);
return dayjs(timeWithNoTZ).format();
};
export const formatToDesiredTimezone = (time, timezone) => {
return dayjs().tz(timezone).utcOffset() ? dayjs(time).tz(timezone, true) : dayjs(time).utc(true);
};
const DateRangePickerComponent = ({
from,
to,
hourFrom = "00:00:00",
hourTo = "23:59:59",
onUpdate = () => null,
width,
label = null,
backgroundColor = Palette.WHITE,
borderColor = Palette.DIM_GREY,
hideHourFilter = false,
timezoneId,
rangeLimit,
minimalDateFormat = "M/DD",
compactDateFormat = "YYYY-MM-DD hh:mm a",
weekStartsOn = 0,
maxDate = null,
onlyPastDates = false,
materialInputFormat = false,
locale = enUS,
title = "Date and time range",
saveText = "Save",
cancelText = "Cancel",
timeOfDayText = "Time of day",
timeStaticRanges = {}
}) => {
const [open, setOpen] = useState(false);
const [hourRange, setHourRange] = useState([formatHoursToNumber(hourFrom), formatHoursToNumber(hourTo, true)]);
const [partialDate, setPartialDate] = useState(JSON.parse(JSON.stringify({
from,
to
})));
useEffect(() => {
let isMounted = true;
if (isMounted) {
setPartialDate(JSON.parse(JSON.stringify({
from,
to
})));
}
return () => {
isMounted = false;
};
}, [to, from]);
const selectorWidth = width || (hideHourFilter ? 120 : "auto");
const is24sFormat = compactDateFormat.slice(-1) !== "a";
const rangeToZeroHour = range => {
const {
hourFrom,
hourTo
} = getHourRange(hourRange);
const from = formatToDesiredTimezone(range.from, timezoneId).startOf("day").format();
const to = formatToDesiredTimezone(range.to, timezoneId).endOf("day").format();
return {
from,
to,
hourFrom,
hourTo
};
};
const togglePopover = () => setOpen(!open);
const forceClosePopover = () => setOpen(false);
const toToShow = formatToLocalTimezone(partialDate.to);
const fromToShow = formatToLocalTimezone(partialDate.from);
const format = date => dayjs(date).format(minimalDateFormat);
let textToShow = `${format(fromToShow)} - ${format(toToShow)}`;
const marks = getHourRangeMarks(is24sFormat);
if (!hideHourFilter) textToShow += ` — ${marks[hourRange[0]]} - ${marks[hourRange[1]]}`;
const mobile = window.innerWidth < 900;
return _jsxs(_Fragment, {
children: [_jsx(Modal, {
hideButtons: false,
visible: open,
modalTitle: title,
onClose: () => {
setPartialDate(JSON.parse(JSON.stringify({
from,
to
})));
forceClosePopover();
},
onConfirm: () => {
const range = partialDate;
onUpdate(rangeToZeroHour(range));
forceClosePopover();
},
width: mobile ? 350 : 920,
height: hideHourFilter ? 540 : 650,
okButton: saveText,
cancelButton: cancelText,
noPadding: true,
children: _jsxs(Column, {
style: {
width: "100%",
height: "100%",
font: FontStyles.BODY2_FONT
},
children: [_jsx(DayRangePicker, {
mobile: mobile,
weekStartsOn: weekStartsOn,
rangeLimit: rangeLimit,
maxDate: maxDate,
onlyPastDates: onlyPastDates,
language: locale,
timeStaticRanges: timeStaticRanges,
update: range => {
const preferedZoneStr = timezoneId;
if (!range.selection.startDate || !range.selection.endDate) {
return;
}
const from = formatToDesiredTimezone(range.selection.startDate, preferedZoneStr).startOf("day");
const to = formatToDesiredTimezone(range.selection.endDate, preferedZoneStr).endOf("day");
setPartialDate({
from,
to
});
},
to: toToShow,
from: fromToShow,
timezoneId: timezoneId
}), rangeLimit && _jsxs(Row, {
style: {
color: Palette.ERROR_RED,
marginLeft: 16
},
children: ["Max range: ", rangeLimit, " days"]
}), !hideHourFilter && _jsx(HourRangePicker, {
label: timeOfDayText,
isMobile: mobile,
defaultValue: hourRange,
onAfterChange: setHourRange,
isStandardFormat: is24sFormat
})]
})
}), _jsxs(SelectorWrapper, {
children: [materialInputFormat && _jsx(Column, {
"data-testid": "date-range",
style: {
marginTop: 8,
marginBottom: -20
},
children: _jsx(MaterialInput, {
label: label,
iconEnd: _jsx(Icons.CalendarIcon, {
onClick: () => togglePopover()
}),
width: selectorWidth,
onFocus: () => togglePopover(),
value: textToShow,
readOnly: true
})
}), !materialInputFormat && label && _jsx(LabelWrapper, {
children: label
}), !materialInputFormat && _jsx(FakeSelector, {
width: selectorWidth,
backgroundColor: backgroundColor,
borderColor: borderColor,
onClick: () => togglePopover(),
children: _jsxs(Row, {
style: {
font: FontStyles.BODY2_FONT
},
children: [_jsx(Column, {
style: {
marginRight: 8,
marginTop: 1
},
children: _jsx(Icons.CalendarIcon, {
size: 15
})
}), _jsx(Column, {
"data-testid": "date-range",
children: textToShow
})]
})
})]
}), _jsx(Helmet, {
children: _jsx("style", {
children: `
.rdrMonths .rdrMonth {
position: relative;
}
.rdrMonths .rdrMonth:first-child {
border-right: solid 1px #eff2f7;
}
.rdrMonths .rdrMonth .rdrMonthName {
position: absolute;
top: -50px;
left: auto;
right: 32px;
font-family: 'Poppins';
font-size: 16px;
font-weight: 500;
color: ${Palette.BLACK};
}
.rdrMonths .rdrMonth:first-child .rdrMonthName {
left: 32px;
right: auto;
}
.rdrInRange {
background: ${Palette.WHITE_SMOKE} !important;
}
.rdrStaticRangeSelected{
background: ${Palette.BLACK} !important;
color: ${Palette.WHITE} !important;
}
.rdrStaticRangeSelected span.rdrStaticRangeLabel {
color: ${Palette.WHITE} !important;
}
.rdrStaticRangeSelected:hover span.rdrStaticRangeLabel,
.rdrStaticRangeSelected span.rdrStaticRangeLabel:hover {
color: ${Palette.BLACK} !important;
}
.rdrDayToday .rdrDayNumber span:after {
background: ${Palette.PRIMARY}
}
.rdrDayEndPreview,
.rdrEndEdge {
border-top-right-radius: 3em;
border-bottom-right-radius: 3em;
right: 19%;
}
.rdrDayStartPreview,
.rdrStartEdge {
border-top-left-radius: 3em;
border-bottom-left-radius: 3em;
left: 19%;
}
.rdrDayToday .rdrDayNumber {
border: 1px solid ${Palette.DARK_GREY};
border-radius: 50px;
left: 21%;
right: 21%;
}
.rdrDefinedRangesWrapper {
margin: 8px 0 0 8px;
}
.rdrDefinedRangesWrapper button {
border-radius: 4px;
border: 1px transparent;
}
span.rdrStaticRangeLabel {
line-height: 16px;
}
.rdrNextPrevButton {
background: transparent;
}
.rdrDayToday:not(.rdrDayPassive) .rdrStartEdge ~ .rdrDayNumber span:after,
.rdrDayToday:not(.rdrDayPassive) .rdrEndEdge ~ .rdrDayNumber span:after
.rdrDayToday .rdrDayNumber span:after {
background:none;
}
`
})
})]
});
};
export default DateRangePickerComponent;