FarmBot/Farmbot-Web-App

View on GitHub
frontend/sensors/sensor_readings/time_period_selection.tsx

Summary

Maintainability
A
1 hr
Test Coverage
import React from "react";
import { FBSelect, Row, Col, BlurableInput } from "../../ui";
import moment from "moment";
import { TaggedSensorReading } from "farmbot";
import { TimePeriodSelectionProps, DateDisplayProps } from "./interfaces";
import { cloneDeep } from "lodash";
import { t } from "../../i18next_wrapper";
import { TimeSettings } from "../../interfaces";

/** Look up time period label by seconds. */
const timePeriodLookup = () => ({
  [60 * 60 * 24]: t("Day"),
  [60 * 60 * 24 * 7]: t("Week"),
  [60 * 60 * 24 * 30]: t("Month"),
  [60 * 60 * 24 * 365]: t("Year"),
});

/** For time period selection dropdown. */
const timePeriodList = () => Object.entries(timePeriodLookup())
  .map(([value, label]) => ({ value, label }));

const blurableInputDateFormat = "YYYY-MM-DD";

const today = moment().startOf("day").unix();

/** Return default time period end date sensor readings widget state. */
export const getEndDate = (sensorReadings: TaggedSensorReading[]) =>
  sensorReadings.length > 0
    ? moment(cloneDeep(sensorReadings).reverse()[0]
      .body.read_at).startOf("day").unix()
    : today;

enum ColWidth {
  period = 3,
  endDate = 5,
  showPrevious = 4,
}

/** Specify a time period by end date and duration. */
export const TimePeriodSelection = (props: TimePeriodSelectionProps) => {
  const { timePeriod, endDate, showPreviousPeriod,
    setEndDate, setPeriod, togglePrevious } = props;
  return <div className="sensor-history-time-selection">
    <Row>
      <Col xs={ColWidth.period}>
        <label>{t("Time period")}</label>
      </Col>
      <Col xs={ColWidth.endDate}>
        <label style={{ display: "inline" }}>{t("Period End Date")}</label>
        <i className={"fa fa-clock-o fb-icon-button"}
          style={{ marginLeft: "1rem" }}
          onClick={() => setEndDate(today)} />
      </Col>
      <Col xs={ColWidth.showPrevious}>
        <label>{t("Show Previous Period")}</label>
      </Col>
    </Row>
    <Row>
      <Col xs={ColWidth.period}>
        <FBSelect
          key={timePeriod}
          selectedItem={
            { label: timePeriodLookup()[timePeriod], value: timePeriod }}
          onChange={ddi => setPeriod(parseInt("" + ddi.value))}
          list={timePeriodList()} />
      </Col>
      <Col xs={ColWidth.endDate}>
        <BlurableInput
          type="date"
          value={moment.unix(endDate).format(blurableInputDateFormat)}
          onCommit={e => setEndDate(moment(e.currentTarget.value,
            blurableInputDateFormat).unix())} />
      </Col>
      <Col xs={ColWidth.showPrevious}>
        <div className="fb-checkbox large">
          <input type="checkbox"
            name="previous"
            checked={showPreviousPeriod}
            onChange={togglePrevious} />
        </div>
      </Col>
    </Row>
  </div>;
};

/** Format date for widget footer display. */
const formatFooterDate = (unix: number, timeSettings: TimeSettings) =>
  moment.unix(unix).utcOffset(timeSettings.utcOffset).format("MMMM D");

/** Display sensor reading date filter settings. */
export const DateDisplay = (props: DateDisplayProps) => {
  const { endDate, timeSettings, timePeriod, showPreviousPeriod } = props;
  const dateRange = (end: number) => {
    const begin = formatFooterDate(end - timePeriod, timeSettings);
    return timePeriod > 60 * 60 * 24
      ? `${begin}–${formatFooterDate(end, timeSettings)}`
      : formatFooterDate(end, timeSettings);
  };
  return <div className="date">
    <label>{t("Date")}:</label>
    <span>
      {dateRange(endDate)}
    </span>
    {showPreviousPeriod &&
      <span style={{ color: "gray" }}>
        {" (" + dateRange(endDate - timePeriod) + ")"}
      </span>}
  </div>;
};