redbadger/pride-london-app

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

Summary

Maintainability
A
0 mins
Test Coverage
// @flow
import React, { Component } from "react";
import { View, TouchableWithoutFeedback, StyleSheet } from "react-native";
import { equals } from "ramda";
import {
  toLondonFormat,
  now,
  isBefore,
  isSameDay,
  FORMAT_WEEKDAY_MONTH_DAY
} from "../../lib/date";

import Text from "../../components/Text";

import {
  dateRangePickerSelectedColor,
  dateRangePickerTextColor,
  mediumGreyColor
} from "../../constants/colors";

export type CalendarDay = {
  year: number,
  month: number,
  day: number,
  timestamp: number,
  dateString: string
};

export type DayMarkings = {
  [string]: DayMarking
};

type DayMarking = {
  selected?: true,
  startingDay?: true,
  endingDay?: true,
  marked?: true
};

type DayProps = {
  marking: DayMarking,
  date: CalendarDay,
  onPress: Function,
  onLongPress: Function
};

const textStyle = (marking: DayMarking, disabled: boolean) => [
  styles.text,
  marking.selected ? styles.selectedText : {},
  disabled ? styles.disabledText : {}
];

const leftFillerStyle = (marking: DayMarking) => [
  styles.filler,
  marking.selected && !marking.startingDay
    ? { backgroundColor: dateRangePickerSelectedColor }
    : { backgroundColor: "transparent" }
];

const rightFillerStyle = (marking: DayMarking) => [
  styles.filler,
  marking.selected && !marking.endingDay
    ? { backgroundColor: dateRangePickerSelectedColor }
    : { backgroundColor: "transparent" }
];

const dayStyle = (marking: DayMarking) => [
  styles.day,
  marking.selected
    ? { backgroundColor: dateRangePickerSelectedColor }
    : { backgroundColor: "transparent" }
];

const dotStyle = (marking: DayMarking) => [
  styles.dot,
  marking.selected
    ? { backgroundColor: dateRangePickerTextColor }
    : { backgroundColor: dateRangePickerSelectedColor }
];

export default class Day extends Component<DayProps> {
  static defaultProps = {
    disabled: false
  };

  shouldComponentUpdate = (nextProps: DayProps): boolean => {
    const { marking, date } = this.props;
    const { marking: nextMarking, date: nextDate } = nextProps;

    return !equals(marking, nextMarking) || !equals(date, nextDate);
  };

  onPress = () => {
    this.props.onPress(this.props.date);
  };

  onLongPress = () => {
    this.props.onLongPress(this.props.date);
  };

  render() {
    const { marking, date } = this.props;
    const dateNow = now();
    const disabled =
      isBefore(date.dateString, dateNow) &&
      !isSameDay(date.dateString, dateNow);
    const label = toLondonFormat(date.dateString, FORMAT_WEEKDAY_MONTH_DAY);
    const traits = marking.selected ? ["button", "selected"] : ["button"];

    return (
      <TouchableWithoutFeedback
        onPress={this.onPress}
        onLongPress={this.onLongPress}
        accessibilityTraits={disabled ? ["button", "disabled"] : traits}
        accessibilityLabel={label}
        accessibilityComponentType="button"
        disabled={disabled}
        testID={`calendar-day-${date.year}-${date.month}-${date.day}`}
      >
        <View style={styles.container}>
          {marking.selected && (
            <View style={styles.overlay}>
              <View style={leftFillerStyle(marking)} />
              <View style={rightFillerStyle(marking)} />
            </View>
          )}
          <View style={dayStyle(marking)}>
            <Text type="small" style={textStyle(marking, disabled)}>
              {date.day}
            </Text>
          </View>
          {marking.marked && (
            <View style={styles.overlay}>
              <View style={dotStyle(marking)} />
            </View>
          )}
        </View>
      </TouchableWithoutFeedback>
    );
  }
}

const FILLER_HEIGHT = 35;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    alignSelf: "stretch"
  },
  overlay: {
    position: "absolute",
    height: FILLER_HEIGHT,
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "flex-end",
    left: 0,
    right: 0
  },
  filler: {
    height: FILLER_HEIGHT,
    flex: 1
  },
  day: {
    width: FILLER_HEIGHT - 1,
    height: FILLER_HEIGHT,
    alignItems: "center",
    borderRadius: 17,
    backgroundColor: dateRangePickerSelectedColor
  },
  text: {
    marginTop: 7,
    textAlign: "center"
  },
  selectedText: {
    color: dateRangePickerTextColor,
    fontWeight: "bold"
  },
  disabledText: {
    color: mediumGreyColor
  },
  dot: {
    width: 4,
    height: 4,
    borderRadius: 2,
    marginBottom: 5
  }
});