import React from "react"; import { withRouter } from "react-router-dom"; import Flatpickr from "react-flatpickr"; import { shiftDays, shiftMonths, formatDay, formatDayShort, formatMonthYYYY, formatISO, isToday, lastMonth, nowForSite, isSameMonth, isThisMonth, parseUTCDate, isBefore, isAfter, } from "./date"; import Transition from "../transition"; import { navigateToQuery, QueryLink, QueryButton } from "./query"; class DatePicker extends React.Component { constructor(props) { super(props); this.handleKeyup = this.handleKeyup.bind(this); this.handleClick = this.handleClick.bind(this); this.state = { mode: "menu", open: false }; } componentDidMount() { document.addEventListener("keyup", this.handleKeyup); document.addEventListener("mousedown", this.handleClick, false); } componentWillUnmount() { document.removeEventListener("keyup", this.handleKeyup); document.removeEventListener("mousedown", this.handleClick, false); } handleKeyup(e) { const { query, history } = this.props; if (e.ctrlKey || e.ctrlKey || e.altKey) return; const newSearch = { period: false, from: false, to: false, date: false, }; const insertionDate = parseUTCDate(this.props.site.insertedAt); if (e.key === "ArrowLeft") { const prevDate = formatISO(shiftDays(query.date, -1)); const prevMonth = formatISO(shiftMonths(query.date, -1)); if ( query.period === "day" && !isBefore(parseUTCDate(prevDate), insertionDate, query.period) ) { newSearch.period = "day"; newSearch.date = prevDate; } else if ( query.period === "month" && !isBefore(parseUTCDate(prevMonth), insertionDate, query.period) ) { newSearch.period = "month"; newSearch.date = prevMonth; } } else if (e.key === "ArrowRight") { const nextDate = formatISO(shiftDays(query.date, 1)); const nextMonth = formatISO(shiftMonths(query.date, 1)); if ( query.period === "day" && !isAfter( parseUTCDate(nextDate), nowForSite(this.props.site), query.period ) ) { newSearch.period = "day"; newSearch.date = nextDate; } else if ( query.period === "month" && !isAfter( parseUTCDate(nextMonth), nowForSite(this.props.site), query.period ) ) { newSearch.period = "month"; newSearch.date = nextMonth; } } if (newSearch.date) { navigateToQuery(history, query, newSearch); } } handleClick(e) { if (this.dropDownNode && this.dropDownNode.contains(e.target)) return; this.setState({ open: false }); } timeFrameText() { const { query, site } = this.props; if (query.period === "day") { if (isToday(site, query.date)) { return "Today"; } return formatDay(query.date); } if (query.period === '7d') { return 'Last 7 days' } if (query.period === '30d') { return 'Last 30 days' } if (query.period === 'month') { if (isThisMonth(site, query.date)) { return 'Month to Date' } return formatMonthYYYY(query.date) } if (query.period === '6mo') { return 'Last 6 months' } if (query.period === '12mo') { return 'Last 12 months' } if (query.period === 'custom') { return `${formatDayShort(query.from)} - ${formatDayShort(query.to)}` } return 'Realtime' } renderArrow(period, prevDate, nextDate) { const insertionDate = parseUTCDate(this.props.site.insertedAt); const disabledLeft = isBefore( parseUTCDate(prevDate), insertionDate, period ); const disabledRight = isAfter( parseUTCDate(nextDate), nowForSite(this.props.site), period ); const leftClasses = `flex items-center px-2 border-r border-gray-300 rounded-l dark:border-gray-500 dark:text-gray-100 ${ disabledLeft ? "bg-gray-200 dark:bg-gray-900" : "" }`; const rightClasses = `flex items-center px-2 rounded-r dark:text-gray-100 ${ disabledRight ? "bg-gray-200 dark:bg-gray-900" : "" }`; return (
); } renderArrows() { const { query } = this.props; if (query.period === "month") { const prevDate = formatISO(shiftMonths(query.date, -1)); const nextDate = formatISO(shiftMonths(query.date, 1)); return this.renderArrow("month", prevDate, nextDate); } if (query.period === "day") { const prevDate = formatISO(shiftDays(query.date, -1)); const nextDate = formatISO(shiftDays(query.date, 1)); return this.renderArrow("day", prevDate, nextDate); } } open() { this.setState({ mode: "menu", open: true }); } renderDropDown() { return (
(this.dropDownNode = node)} > {this.renderDropDownContent()}
); } close() { this.setState({ open: false }); } renderLink(period, text, opts = {}) { const { query, site } = this.props; let boldClass; if (query.period === "day" && period === "day") { boldClass = isToday(site, query.date) ? "font-bold" : ""; } else if (query.period === "month" && period === "month") { const linkDate = opts.date || nowForSite(site); boldClass = isSameMonth(linkDate, query.date) ? "font-bold" : ""; } else { boldClass = query.period === period ? "font-bold" : ""; } const date = opts.date ? formatISO(opts.date) : false; return ( {text} ); } renderDropDownContent() { if (this.state.mode === "menu") { return (
{this.renderLink("day", "Today")} {this.renderLink("realtime", "Realtime")}
{this.renderLink("7d", "Last 7 days")} {this.renderLink("30d", "Last 30 days")}
{ this.renderLink('month', 'Month to Date') } { this.renderLink('month', 'Last month', {date: lastMonth(this.props.site)}) }
{this.renderLink("6mo", "Last 6 months")} {this.renderLink("12mo", "Last 12 months")}
this.setState({mode: 'calendar'}, this.openCalendar.bind(this))} onKeyPress={() => this.setState({mode: 'calendar'}, this.openCalendar.bind(this))} className="block px-4 py-2 md:text-sm leading-tight hover:bg-gray-100 dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100 cursor-pointer" tabIndex="0" role="button" aria-haspopup="true" aria-expanded="false" aria-controls="calendar" > Custom range
); } if (this.state.mode === "calendar") { const insertionDate = new Date(this.props.site.insertedAt); const dayBeforeCreation = insertionDate - 86400000; return ( this.calendar = calendar} className="invisible" onChange={this.setCustomDate.bind(this)} /> ) } } setCustomDate(dates) { if (dates.length === 2) { const [from, to] = dates if (formatISO(from) === formatISO(to)) { navigateToQuery( this.props.history, this.props.query, { period: 'day', date: formatISO(from), from: false, to: false, } ) } else { navigateToQuery( this.props.history, this.props.query, { period: 'custom', date: false, from: formatISO(from), to: formatISO(to), } ) } this.close() } } openCalendar() { this.calendar && this.calendar.flatpickr.open(); } render() { return (
{ this.renderArrows() } { this.renderDropDown() }
); } } export default withRouter(DatePicker);