anyone-oslo/pages

View on GitHub
app/javascript/components/DateRangeSelect.tsx

Summary

Maintainability
B
6 hrs
Test Coverage
import { useCallback, useEffect, useState } from "react";

import DateTimeSelect from "./DateTimeSelect";

type Props = {
  objectName: string;
  startsAt: Date | string;
  endsAt: Date | string;
  setStartsAt?: (date: Date) => void;
  setEndsAt?: (date: Date) => void;
  disabled?: boolean;
  disableTime?: boolean;
}

function defaultDate(offset = 0): Date {
  const coeff = 1000 * 60 * 60;
  return new Date(
    Math.round(new Date().getTime() / coeff) * coeff +
      coeff +
      1000 * 60 * offset
  );
}

function parseDate(str: Date | string): Date {
  if (!str) {
    return null;
  } else if (typeof str === "string") {
    return new Date(str);
  } else {
    return str;
  }
}

export default function DateRangeSelect(props: Props) {
  const { disabled, disableTime, objectName } = props;

  const [uncontrolledStartsAt, setUncontrolledStartsAt] = useState(
    parseDate(props.startsAt)
  );

  const [uncontrolledEndsAt, setUncontrolledEndsAt] = useState(
    parseDate(props.endsAt) || defaultDate(60)
  );

  const startsAt = parseDate(
    props.setStartsAt ? props.startsAt : uncontrolledStartsAt
  );
  const setStartsAt = props.setStartsAt || setUncontrolledStartsAt;

  const endsAt = parseDate(props.setEndsAt ? props.endsAt : uncontrolledEndsAt);
  const setEndsAt = props.setEndsAt || setUncontrolledEndsAt;

  const setDates = useCallback(
    (start: Date, end: Date) => {
      if (end < start) {
        end = start;
      }
      setStartsAt(start);
      setEndsAt(end);
    },
    [setStartsAt, setEndsAt]
  );

  const changeStartsAt = (newDate: Date) => {
    setDates(
      newDate,
      new Date(endsAt.getTime() + (newDate.getTime() - startsAt.getTime()))
    );
  };

  const changeEndsAt = (newDate: Date) => {
    setDates(startsAt, newDate);
  };

  useEffect(() => {
    if (!startsAt || !endsAt) {
      setDates(startsAt || defaultDate(), endsAt || defaultDate(60));
    }
  }, [startsAt, endsAt, setDates]);

  return (
    <div className="date-range-select">
      {startsAt && (
        <div className="date">
          <DateTimeSelect
            name={objectName + "[starts_at]"}
            disabled={disabled}
            disableTime={disableTime}
            onChange={changeStartsAt}
            value={startsAt}
          />
        </div>
      )}
      <span className="to">to</span>
      {endsAt && (
        <div className="date">
          <DateTimeSelect
            name={objectName + "[ends_at]"}
            disabled={disabled}
            disableTime={disableTime}
            onChange={changeEndsAt}
            value={endsAt}
          />
        </div>
      )}
    </div>
  );
}