text: import React, { Fragment } from "react";
  import { withRouter } from "react-router-dom";
  import Flatpickr from "react-flatpickr";
  import { ChevronDownIcon } from '@heroicons/react/solid'
  import { Transition } from '@headlessui/react'
  import {
    shiftDays,
    shiftMonths,
    formatDay,
    formatDayShort,
    formatMonthYYYY,
    formatYear,
    formatISO,
    isToday,
    lastMonth,
    nowForSite,
    isSameMonth,
    isThisMonth,
    isThisYear,
    parseUTCDate,
    isBefore,
    isAfter,
  } from "./util/date";
  import { navigateToQuery, QueryLink, QueryButton } from "./query";
  
  function renderArrow(query, site, period, prevDate, nextDate) {
    const insertionDate = parseUTCDate(site.statsBegin);
    const disabledLeft = isBefore(
      parseUTCDate(prevDate),
      insertionDate,
      period
    );
    const disabledRight = isAfter(
      parseUTCDate(nextDate),
      nowForSite(site),
      period
    );
  
    const leftClasses = `flex items-center px-1 sm:px-2 border-r border-gray-300 rounded-l
        dark:border-gray-500 dark:text-gray-100 ${
        disabledLeft ? "bg-gray-300 dark:bg-gray-950" : "hover:bg-gray-100 dark:hover:bg-gray-900"
      }`;
    const rightClasses = `flex items-center px-1 sm:px-2 rounded-r dark:text-gray-100 ${
        disabledRight ? "bg-gray-300 dark:bg-gray-950" : "hover:bg-gray-100 dark:hover:bg-gray-900"
      }`;
    return (
      <div className="flex rounded shadow bg-white mr-2 sm:mr-4 cursor-pointer dark:bg-gray-800">
        <QueryButton
          to={{ date: prevDate }}
          query={query}
          className={leftClasses}
          disabled={disabledLeft}
        >
          <svg
            className="feather h-4 w-4"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
          >
            <polyline points="15 18 9 12 15 6"></polyline>
          </svg>
        </QueryButton>
        <QueryButton
          to={{ date: nextDate }}
          query={query}
          className={rightClasses}
          disabled={disabledRight}
        >
          <svg
            className="feather h-4 w-4"
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth="2"
            strokeLinecap="round"
            strokeLinejoin="round"
          >
            <polyline points="9 18 15 12 9 6"></polyline>
          </svg>
        </QueryButton>
      </div>
    );
  }
  
  function DatePickerArrows({site, query}) {
    if (query.period === "year") {
      const prevDate = formatISO(shiftMonths(query.date, -12));
      const nextDate = formatISO(shiftMonths(query.date, 12));
  
      return renderArrow(query, site, "year", prevDate, nextDate);
    } else if (query.period === "month") {
      const prevDate = formatISO(shiftMonths(query.date, -1));
      const nextDate = formatISO(shiftMonths(query.date, 1));
  
      return renderArrow(query, site, "month", prevDate, nextDate);
    } else if (query.period === "day") {
      const prevDate = formatISO(shiftDays(query.date, -1));
      const nextDate = formatISO(shiftDays(query.date, 1));
  
      return renderArrow(query, site, "day", prevDate, nextDate);
    }
  
    return null
  }
  
  class DatePicker extends React.Component {
    constructor(props) {
      super(props);
      this.handleKeydown = this.handleKeydown.bind(this);
      this.handleClick = this.handleClick.bind(this);
      this.setCustomDate = this.setCustomDate.bind(this);
      this.openCalendar = this.openCalendar.bind(this);
      this.close = this.close.bind(this);
      this.toggle = this.toggle.bind(this);
      this.state = { mode: "menu", open: false };
    }
  
    componentDidMount() {
      document.addEventListener("keydown", this.handleKeydown);
      document.addEventListener("mousedown", this.handleClick, false);
    }
  
    componentWillUnmount() {
      document.removeEventListener("keydown", this.handleKeydown);
      document.removeEventListener("mousedown", this.handleClick, false);
    }
  
    handleKeydown(e) {
      const { query, history } = this.props;
  
      if (e.target.tagName === 'INPUT') return true;
      if (e.ctrlKey || e.metaKey || e.altKey || e.isComposing || e.keyCode === 229) return true;
  
      const newSearch = {
        period: false,
        from: false,
        to: false,
        date: false,
      };
  
      const insertionDate = parseUTCDate(this.props.site.statsBegin);
  
      if (e.key === "ArrowLeft") {
        const prevDate = formatISO(shiftDays(query.date, -1));
        const prevMonth = formatISO(shiftMonths(query.date, -1));
        const prevYear = formatISO(shiftMonths(query.date, -12));
  
        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 (query.period === "year" && !isBefore(parseUTCDate(prevYear), insertionDate, query.period)) {
          newSearch.period = "year";
          newSearch.date = prevYear;
        }
      } else if (e.key === "ArrowRight") {
        const now = nowForSite(this.props.site)
        const nextDate = formatISO(shiftDays(query.date, 1));
        const nextMonth = formatISO(shiftMonths(query.date, 1));
        const nextYear = formatISO(shiftMonths(query.date, 12));
  
        if (query.period === "day" && !isAfter(parseUTCDate(nextDate), now, query.period)) {
          newSearch.period = "day";
          newSearch.date = nextDate;
        } else if (query.period === "month" && !isAfter(parseUTCDate(nextMonth), now, query.period)) {
          newSearch.period = "month";
          newSearch.date = nextMonth;
        } else if (query.period === "year" && !isAfter(parseUTCDate(nextYear), now, query.period)) {
          newSearch.period = "year";
          newSearch.date = nextYear;
        }
      }
  
      this.setState({open: false});
  
      const keys = ['d', 'e', 'r', 'w', 'm', 'y', 't', 's', 'l', 'a'];
      const redirects = [{date: false, period: 'day'}, {date: shiftDays(nowForSite(this.props.site), -1), period: 'day'}, {period: 'realtime'}, {date: false, period: '7d'}, {date: false, period: 'month'}, {date: false, period: 'year'}, {date: false, period: '30d'}, {date: false, period: '6mo'}, {date: false, period: '12mo'}, {date: false, period: 'all'}];
  
      if (keys.includes(e.key.toLowerCase())) {
        navigateToQuery(history, query, {...newSearch, ...(redirects[keys.indexOf(e.key.toLowerCase())])});
      } else if (e.key.toLowerCase() === 'c') {
        this.setState({mode: 'calendar', open: true}, this.openCalendar);
      } else if (newSearch.date) {
        navigateToQuery(history, query, newSearch);
      }
    }
  
    handleClick(e) {
      if (this.dropDownNode && this.dropDownNode.contains(e.target)) return;
  
      this.setState({ open: false });
    }
  
    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()
      }
    }
  
    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 === 'year') {
        if (isThisYear(site, query.date)) {
          return 'Year to Date'
        }
        return formatYear(query.date)
      } if (query.period === 'all') {
        return 'All time'
      } if (query.period === 'custom') {
        return `${formatDayShort(query.from)} - ${formatDayShort(query.to)}`
      }
      return 'Realtime'
    }
  
    toggle() {
      const newMode = this.state.mode === 'calendar' && !this.state.open ? 'menu' : this.state.mode
      this.setState(prevState => ({ mode: newMode, open: !prevState.open }));
    }
  
    close() {
      this.setState({ open: false });
    }
  
    openCalendar() {
      this.calendar && this.calendar.flatpickr.open();
    }
  
    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" : "";
      }
  
      opts.date = opts.date ? formatISO(opts.date) : false;
  
      const keybinds = {
        'Today': 'D',
        'Realtime': 'R',
        'Last 7 days': 'W',
        'Month to Date': 'M',
        'Year to Date': 'Y',
        'Last 12 months': 'L',
        'Last 30 days': 'T',
        'All time': 'A',
      };
  
      return (
        <QueryLink
          to={{from: false, to: false, period, ...opts}}
          onClick={this.close}
          query={this.props.query}
          className={`${boldClass  } px-4 py-2 text-sm leading-tight hover:bg-gray-100 hover:text-gray-900
            dark:hover:bg-gray-900 dark:hover:text-gray-100 flex items-center justify-between`}
        >
          {text}
          <span className='font-normal'>{keybinds[text]}</span>
        </QueryLink>
      );
    }
  
    renderDropDownContent() {
      const { site } = this.props
  
      if (this.state.mode === "menu") {
        return (
          <div
            id="datemenu"
            className="absolute w-full left-0 right-0 md:w-56 md:absolute md:top-auto md:left-auto md:right-0 mt-2 origin-top-right z-10"
          >
            <div
              className="rounded-md shadow-lg  bg-white dark:bg-gray-800 ring-1 ring-black ring-opacity-5
              font-medium text-gray-800 dark:text-gray-200 date-options"
            >
              <div className="py-1 border-b border-gray-200 dark:border-gray-500 date-option-group">
                {this.renderLink("day", "Today")}
                {this.renderLink("realtime", "Realtime")}
              </div>
              <div className="py-1 border-b border-gray-200 dark:border-gray-500 date-option-group">
                {this.renderLink("7d", "Last 7 days")}
                {this.renderLink("30d", "Last 30 days")}
              </div>
              <div className="py-1 border-b border-gray-200 dark:border-gray-500 date-option-group">
                { this.renderLink('month', 'Month to Date') }
                { this.renderLink('month', 'Last month', {date: lastMonth(site)}) }
              </div>
              <div className="py-1 border-b border-gray-200 dark:border-gray-500 date-option-group">
                {this.renderLink("year", "Year to Date")}
                {this.renderLink("12mo", "Last 12 months")}
              </div>
              <div className="py-1 date-option-group">
                {this.renderLink("all", "All time")}
                <span
                  onClick={() => this.setState({mode: 'calendar'}, this.openCalendar)}
                  onKeyPress={() => this.setState({mode: 'calendar'}, this.openCalendar)}
                  className="px-4 py-2 text-sm leading-tight hover:bg-gray-100
                    dark:hover:bg-gray-900 hover:text-gray-900 dark:hover:text-gray-100
                    cursor-pointer flex items-center justify-between"
                  tabIndex="0"
                  role="button"
                  aria-haspopup="true"
                  aria-expanded="false"
                  aria-controls="calendar"
                >
                  Custom range
                  <span className='font-normal'>C</span>
                </span>
              </div>
            </div>
          </div>
        );
      } if (this.state.mode === "calendar") {
        const insertionDate = new Date(this.props.site.statsBegin);
        const dayBeforeCreation = insertionDate - 86400000;
        return (
          <div className="h-0">
            <Flatpickr
              id="calendar"
              options={{
                mode: 'range',
                maxDate: 'today',
                minDate: dayBeforeCreation,
                showMonths: 1,
                static: true,
                animate: true}}
              ref={calendar => this.calendar = calendar}
              className="invisible"
              onChange={this.setCustomDate}
            />
          </div>
          )
      }
    }
  
    renderPicker() {
      return (
        <div
          className="w-20 sm:w-36 md:w-48 md:relative"
          ref={(node) => (this.dropDownNode = node)}
        >
          <div
            onClick={this.toggle}
            onKeyPress={this.toggle}
            className="flex items-center justify-between rounded bg-white dark:bg-gray-800 shadow px-2 md:px-3
            py-2 leading-tight cursor-pointer text-xs md:text-sm text-gray-800
            dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-gray-900"
            tabIndex="0"
            role="button"
            aria-haspopup="true"
            aria-expanded="false"
            aria-controls="datemenu"
          >
            <span className="truncate mr-1 md:mr-2">
              {this.props.leadingText}
              <span className="font-medium">{this.timeFrameText()}</span>
            </span>
            <ChevronDownIcon className="hidden sm:inline-block h-4 w-4 md:h-5 md:w-5 text-gray-500" />
          </div>
  
          <Transition
            show={this.state.open}
            as={Fragment}
            enter="transition ease-out duration-100"
            enterFrom="transform opacity-0 scale-95"
            enterTo="transform opacity-100 scale-100"
            leave="transition ease-in duration-75"
            leaveFrom="transform opacity-100 scale-100"
            leaveTo="transform opacity-0 scale-95"
          >
            {this.renderDropDownContent()}
          </Transition>
        </div>
      );
    }
  
    render() {
      return (
        <div className="flex ml-auto pl-2">
          <DatePickerArrows site={this.props.site} query={this.props.query} />
          {this.renderPicker()}
        </div>
      )
    }
  }
  
  export default withRouter(DatePicker);
  