Manual Reference Source

basic/TimePicker.js

/**
 * Created by jakubniezgoda on 20/12/2018.
 */

import PropTypes from 'prop-types';
import React from 'react';

import { Button, Form, Popup } from './index';

/**
 * TimePicker is a component showing datetime picker
 *
 *
 * ## Access
 * `Stage.Basic.TimePicker`
 *
 * ## Usage
 * ![TimePicker](manual/asset/TimePicker_0.png)
 *
 * ```
 * <TimePicker name='scheduledTime' value={this.state.scheduledTime} defaultValue=''
 *             minDate={moment()} maxDate={moment().add(1, 'Y')}
 *             onChange={(event, field) => this.setState({scheduledTime: field.value, queue: false})} />
 * ```
 *
 */
export default class TimePicker extends React.Component {
    constructor(props, context) {
        super(props, context);

        this.state = TimePicker.initialState;
    }

    static TIME_FORMAT = 'HH:mm';

    static DATE_FORMAT = 'YYYY-MM-DD';

    static DATETIME_FORMAT = `${TimePicker.DATE_FORMAT} ${TimePicker.TIME_FORMAT}`;

    /**
     * propTypes
     *
     * @property {string} name name of the field
     * @property {object} defaultValue string data value to be set when Reset button is clicked
     * @property {object} value string data value
     * @property {string} [placaholder=''] input field placeholder
     * @property {number} [timeIntervals=5] time interval between available time options (in minutes)
     * @property {object} [minDate=undefined] moment object for minimal date available in picker
     * @property {object} [maxDate=undefined] moment object for maximal date available in picker
     * @property {Function} [onChange=(function (event, data) {});] function called on data picker change
     */
    static propTypes = {
        defaultValue: PropTypes.string.isRequired,
        name: PropTypes.string.isRequired,
        value: PropTypes.string.isRequired,

        minDate: PropTypes.object,
        maxDate: PropTypes.object,
        onChange: PropTypes.func,
        placeholder: PropTypes.string,
        timeIntervals: PropTypes.number
    };

    static defaultProps = {
        minDate: undefined,
        maxDate: undefined,
        onChange: _.noop,
        placeholder: TimePicker.DATETIME_FORMAT,
        timeIntervals: 5
    };

    static initialState = {
        dateError: false,
        dateValue: null,
        dirty: false,
        isOpen: false
    };

    static getDateString(momentDate) {
        return moment(momentDate).format(TimePicker.DATETIME_FORMAT);
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.value !== TimePicker.getDateString(prevState.dateValue)) {
            return TimePicker.getDateState(prevState.dateValue, nextProps.value);
        }
        return null;
    }

    static getDateState(currentMomentDate, newStringDate) {
        return _.isEmpty(newStringDate)
            ? { dateError: false, dateValue: undefined }
            : moment(newStringDate).isValid()
            ? { dateError: false, dateValue: currentMomentDate }
            : { dateError: true, dateValue: undefined };
    }

    handleDataPickerChange(proxy, field) {
        const value = TimePicker.getDateString(field.value);
        this.setState({ dirty: !_.isEqual(value, this.props.defaultValue), dateValue: field.value, dateError: false });
        this.props.onChange(proxy, { name: this.props.name, value });
    }

    handleInputChange(proxy, field) {
        this.props.onChange(proxy, { name: this.props.name, value: field.value });
        this.setState(TimePicker.getDateState(this.state.dateValue, field.value));
    }

    handleResetButtonClick(proxy) {
        this.props.onChange(proxy, { name: this.props.name, value: this.props.defaultValue });
        this.setState({ dirty: false, ...TimePicker.getDateState(this.state.dateValue, this.props.defaultValue) });
    }

    shouldComponentUpdate(nextProps, nextState) {
        return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
    }

    render() {
        return (
            <Popup
                hoverable
                flowing
                onClose={() => this.setState({ isOpen: false })}
                open={this.state.isOpen}
                position="top right"
            >
                <Popup.Trigger>
                    <Form.Input
                        name="value"
                        value={this.props.value}
                        placeholder={this.props.placeholder}
                        fluid
                        action
                        error={this.state.dateError}
                        onChange={this.handleInputChange.bind(this)}
                        onClick={() => this.setState({ isOpen: false })}
                    >
                        <input />
                        <Button onClick={() => this.setState({ isOpen: true })} icon="calendar" />
                        <Button
                            onClick={this.handleResetButtonClick.bind(this)}
                            icon="cancel"
                            disabled={!this.state.dirty}
                        />
                    </Form.Input>
                </Popup.Trigger>

                <Form.InputDate
                    name="dateValue"
                    value={this.state.dateValue}
                    onChange={this.handleDataPickerChange.bind(this)}
                    minDate={this.props.minDate}
                    maxDate={this.props.maxDate}
                    timeIntervals={this.props.timeIntervals}
                />
            </Popup>
        );
    }
}