redbadger/pride-london-app

View on GitHub
src/screens/DateFilterScreen/DateRangePicker.js

Summary

Maintainability
A
0 mins
Test Coverage
// @flow
import React from "react";
import { CalendarList } from "react-native-calendars";
import Day from "./DateRangePickerDay";
import type { DayMarkings, CalendarDay } from "./DateRangePickerDay";
import type { DateRange } from "../../data/date-time";
import { scaleFont } from "../../components/Text";
import {
  toLondonFormat as formatDate,
  isBefore,
  addDays,
  FORMAT_YEAR_MONTH_DAY
} from "../../lib/date";
import {
  dateRangePickerTextColor,
  lightNavyBlueColor
} from "../../constants/colors";

const getSortedDateRange = (dates: DateRange) =>
  isBefore(dates.endDate, dates.startDate)
    ? { startDate: dates.endDate, endDate: dates.startDate }
    : dates;

const getMarkedDate = (date: string): DayMarkings => ({
  [date]: {
    selected: true,
    startingDay: true,
    endingDay: true
  }
});

const getMarkedDateRange = (dateRange: DateRange): DayMarkings => {
  const { startDate, endDate } = dateRange;
  const markedDates = {};

  // Start
  markedDates[startDate] = {
    selected: true,
    startingDay: true
  };

  // In between
  let inBetweenDate = startDate;
  do {
    inBetweenDate = formatDate(
      addDays(inBetweenDate, 1),
      FORMAT_YEAR_MONTH_DAY
    );
    markedDates[inBetweenDate] = { selected: true };
  } while (inBetweenDate !== endDate);

  // End
  markedDates[endDate] = {
    selected: true,
    endingDay: true
  };

  return markedDates;
};

const addDateMark = (markings: DayMarkings, today: string): DayMarkings => {
  const todayMark = markings[today] || {};

  return {
    ...markings,
    [today]: {
      ...todayMark,
      marked: true
    }
  };
};

const getMarkedDates = (dateRange: ?DateRange, today: string): DayMarkings => {
  if (!dateRange) {
    return addDateMark({}, today);
  }

  if (dateRange.startDate === dateRange.endDate) {
    return addDateMark(getMarkedDate(dateRange.startDate), today);
  }

  return addDateMark(getMarkedDateRange(dateRange), today);
};

const diffFullMonths = (a: Date, b: Date) =>
  12 * (a.getFullYear() - b.getFullYear()) + a.getMonth() - b.getMonth();

type Props = {
  onChange: DateRange => void,
  dateRange?: ?DateRange,
  today?: Date,
  forceNewRange: boolean
};

class DateRangePicker extends React.PureComponent<Props> {
  static defaultProps = {
    dateRange: undefined,
    today: undefined
  };

  onDaySelected = (day: CalendarDay) => {
    const { dateRange, onChange, forceNewRange } = this.props;

    if (
      !dateRange ||
      forceNewRange ||
      dateRange.startDate !== dateRange.endDate
    ) {
      return onChange({ startDate: day.dateString, endDate: day.dateString });
    }

    return onChange(
      getSortedDateRange({
        startDate: dateRange.startDate,
        endDate: day.dateString
      })
    );
  };

  render() {
    const today = this.props.today || new Date();
    const dateRange = this.props.dateRange
      ? getSortedDateRange(this.props.dateRange)
      : this.props.dateRange;
    const current =
      dateRange && this.props.forceNewRange ? dateRange.startDate : null;
    const pastScrollRange = diffFullMonths(
      current ? new Date(current) : today,
      today
    );

    return (
      <CalendarList
        current={current}
        markedDates={getMarkedDates(
          dateRange,
          formatDate(today.toISOString(), FORMAT_YEAR_MONTH_DAY)
        )}
        markingType="period"
        onDayPress={this.onDaySelected}
        dayComponent={Day}
        hideExtraDays
        theme={calendarTheme}
        showScrollIndicator
        pastScrollRange={pastScrollRange}
        futureScrollRange={12}
        calendarHeight={365}
      />
    );
  }
}

const calendarTheme = {
  "stylesheet.calendar.main": {
    week: {
      marginTop: 7,
      marginBottom: 7,
      flexDirection: "row",
      justifyContent: "space-around"
    }
  },
  "stylesheet.calendar.header": {
    monthText: {
      fontFamily: "Poppins-SemiBold",
      fontSize: scaleFont("h2", 18),
      lineHeight: scaleFont("h2", 24),
      marginVertical: 10,
      color: lightNavyBlueColor
    },
    week: {
      marginTop: 7,
      flexDirection: "row",
      justifyContent: "space-around"
    },
    dayHeader: {
      marginTop: 2,
      marginBottom: 7,
      width: 32,
      textAlign: "center",
      fontSize: 14,
      fontFamily: "Roboto",
      color: dateRangePickerTextColor
    }
  }
};

export default DateRangePicker;