UNPKG

@parkassist/pa-ui-library

Version:
335 lines (334 loc) 11.7 kB
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;