# All files / composer/components TimePicker.jsx

50% Statements 13/26
38.89% Branches 7/18
66.67% Functions 8/12
50% Lines 13/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125

    2x

    2x

    2x

    2x

    2x

    144x

    2x
    2x

    2x

    2x

    2x

    24x

    120x

     /**
     * Simple time picker using selects. Works with 12/24h formats.
     *
     * This component is controlled through the time prop, and uses the onChange
     * callback in props to let its parent know of any change.
     */

    import React from 'react';
    import PropTypes from 'prop-types';
    import moment from 'moment-timezone';
    import Select from '../components/Select';

    import styles from './css/TimePicker.css';

    class TimePicker extends React.Component {
      static propTypes = {
        shouldUse24hTime: PropTypes.bool.isRequired,
        onChange: PropTypes.func.isRequired,
        time: PropTypes.instanceOf(moment),
        timezone: PropTypes.string,
        className: PropTypes.string,
      };

      static defaultProps = {
        time: moment(),
      };

      onHourSelectChange = (e) => {
        this.onChange({ hour: e.target.value });
      };

      onMinSelectChange = (e) => {
        this.onChange({ min: e.target.value });
      };

      onPeriodSelectChange = (e) => {
        this.onChange({ dayPeriod: e.target.value });
      };

      /**
       * Moment exposes methods to update a time's hours and minutes, but not day period,
       * so we're using the string parsing method instead
       */
      onChange = (newTimeUnits) => {
        const timeFormats = this.getTimeFormats();
        const timeUnits = this.getTimeUnits();

        const dateFormat = 'YYYY M D';
        const formattedDate = this.props.time.format(dateFormat);

        const hour = typeof newTimeUnits.hour !== 'undefined' ? newTimeUnits.hour : timeUnits.hour;
        const min = typeof newTimeUnits.min !== 'undefined' ? newTimeUnits.min : timeUnits.min;
        const dayPeriod =
          typeof newTimeUnits.dayPeriod !== 'undefined' ? newTimeUnits.dayPeriod : timeUnits.dayPeriod;

        const momentParams = [
          `${formattedDate} ${hour} ${min} ${dayPeriod}`,
          `${dateFormat} ${timeFormats.hour} ${timeFormats.min} ${timeFormats.dayPeriod}`,
        ];

        const time = this.props.timezone ?
                   moment.tz(...momentParams, this.props.timezone) :
                   moment(...momentParams);

        this.props.onChange(time);
      };

      getHoursInDay = () => (
        this.props.shouldUse24hTime ?
          [...Array(24).keys()] : // [0..23]
          [...Array(12 + 1).keys()].slice(1) // [1..12]
      );

      getMinutesInHour = () => [...Array(60).keys()]; // [0..59]

      getTimeFormats = () => ({
        hour: this.props.shouldUse24hTime ? 'H' : 'h',
        min: 'm',
        dayPeriod: this.props.shouldUse24hTime ? ' ' : 'a',
      });

      getTimeUnits = () => {
        const timeFormats = this.getTimeFormats();

        return {
          hour: this.props.time.format(timeFormats.hour),
          min: this.props.time.format(timeFormats.min),
          dayPeriod: this.props.time.format(timeFormats.dayPeriod),
        };
      };

      leftPadTimeUnit = (timeUnit) => (timeUnit < 10 ? `0${timeUnit}` : timeUnit);

      render() {
        const { shouldUse24hTime } = this.props;
        const shouldDisplayPeriodSelect = !shouldUse24hTime;

        const { hour, min, dayPeriod } = this.getTimeUnits();

        const timePickerClassName = this.props.className;

        return (
          <div className={timePickerClassName}>
            <Select onChange={this.onHourSelectChange} value={hour} className={styles.select}>
              {this.getHoursInDay().map((h) =>
                <option value={h} key={h}>{this.leftPadTimeUnit(h)}</option>)}
            </Select>

            <Select onChange={this.onMinSelectChange} value={min} className={styles.select}>
              {this.getMinutesInHour().map((m) =>
                <option value={m} key={m}>{this.leftPadTimeUnit(m)}</option>)}
            </Select>

            {shouldDisplayPeriodSelect &&
              <Select onChange={this.onPeriodSelectChange} value={dayPeriod} className={styles.select}>
                <option value="am">am</option>
                <option value="pm">pm</option>
              </Select>}
          </div>
        );
      }
    }

    export default TimePicker;