|
| 1 | +import React from 'react'; |
1 | 2 | import moment from 'moment';
|
2 |
| -import React, {forwardRef, useEffect, useRef} from 'react'; |
3 | 3 | import _ from 'underscore';
|
| 4 | +import TextInput from '../TextInput'; |
4 | 5 | import CONST from '../../CONST';
|
5 | 6 | import * as Browser from '../../libs/Browser';
|
6 |
| -import TextInput from '../TextInput'; |
7 |
| -import {defaultProps, propTypes} from './datepickerPropTypes'; |
| 7 | +import {propTypes, defaultProps} from './datepickerPropTypes'; |
| 8 | +import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; |
8 | 9 | import './styles.css';
|
9 | 10 |
|
10 | 11 | const datePickerPropTypes = {
|
11 | 12 | ...propTypes,
|
| 13 | + ...windowDimensionsPropTypes, |
12 | 14 | };
|
13 | 15 |
|
14 |
| -function DatePicker({defaultValue, maxDate, minDate, onInputChange, innerRef, label, value, placeholder, errorText, containerStyles, disabled, onBlur}) { |
15 |
| - const inputRef = useRef(null); |
16 |
| - const defaultDateValue = defaultValue ? moment(defaultValue).format(CONST.DATE.MOMENT_FORMAT_STRING) : ''; |
| 16 | +class DatePicker extends React.Component { |
| 17 | + constructor(props) { |
| 18 | + super(props); |
| 19 | + |
| 20 | + this.setDate = this.setDate.bind(this); |
| 21 | + this.showDatepicker = this.showDatepicker.bind(this); |
17 | 22 |
|
18 |
| - useEffect(() => { |
19 |
| - inputRef.current.setAttribute('type', 'date'); |
20 |
| - inputRef.current.setAttribute('max', moment(maxDate).format(CONST.DATE.MOMENT_FORMAT_STRING)); |
21 |
| - inputRef.current.setAttribute('min', moment(minDate).format(CONST.DATE.MOMENT_FORMAT_STRING)); |
22 |
| - inputRef.current.classList.add('expensify-datepicker'); |
23 |
| - }, [maxDate, minDate]); |
| 23 | + this.defaultValue = props.defaultValue ? moment(props.defaultValue).format(CONST.DATE.MOMENT_FORMAT_STRING) : ''; |
| 24 | + } |
| 25 | + |
| 26 | + componentDidMount() { |
| 27 | + // Adds nice native datepicker on web/desktop. Not possible to set this through props |
| 28 | + this.inputRef.setAttribute('type', 'date'); |
| 29 | + this.inputRef.setAttribute('max', moment(this.props.maxDate).format(CONST.DATE.MOMENT_FORMAT_STRING)); |
| 30 | + this.inputRef.setAttribute('min', moment(this.props.minDate).format(CONST.DATE.MOMENT_FORMAT_STRING)); |
| 31 | + this.inputRef.classList.add('expensify-datepicker'); |
| 32 | + } |
24 | 33 |
|
25 | 34 | /**
|
26 | 35 | * Trigger the `onChange` handler when the user input has a complete date or is cleared
|
27 | 36 | * @param {String} text
|
28 | 37 | */
|
29 |
| - const setDate = (text) => { |
| 38 | + setDate(text) { |
30 | 39 | if (!text) {
|
31 |
| - onInputChange(''); |
| 40 | + this.props.onInputChange(''); |
32 | 41 | return;
|
33 | 42 | }
|
34 | 43 |
|
35 | 44 | const asMoment = moment(text, true);
|
36 | 45 | if (asMoment.isValid()) {
|
37 |
| - onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING)); |
| 46 | + this.props.onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING)); |
38 | 47 | }
|
39 |
| - }; |
| 48 | + } |
40 | 49 |
|
41 | 50 | /**
|
42 | 51 | * Pops the datepicker up when we focus this field. This only works on mWeb chrome
|
43 | 52 | * On mWeb chrome the user needs to tap on the field again in order to bring the datepicker. But our current styles
|
44 | 53 | * don't make this very obvious. To avoid confusion we open the datepicker when the user focuses the field
|
45 | 54 | */
|
46 |
| - const showDatepicker = () => { |
47 |
| - if (!inputRef.current || !Browser.isMobileChrome()) { |
| 55 | + showDatepicker() { |
| 56 | + if (!this.inputRef || !Browser.isMobileChrome()) { |
48 | 57 | return;
|
49 | 58 | }
|
50 | 59 |
|
51 |
| - inputRef.current.click(); |
52 |
| - }; |
| 60 | + this.inputRef.click(); |
| 61 | + } |
53 | 62 |
|
54 |
| - return ( |
55 |
| - <TextInput |
56 |
| - forceActiveLabel |
57 |
| - ref={(el) => { |
58 |
| - inputRef.current = el; |
| 63 | + render() { |
| 64 | + return ( |
| 65 | + <TextInput |
| 66 | + forceActiveLabel |
| 67 | + ref={(el) => { |
| 68 | + this.inputRef = el; |
59 | 69 |
|
60 |
| - if (_.isFunction(innerRef)) { |
61 |
| - innerRef(el); |
62 |
| - } |
63 |
| - }} |
64 |
| - onFocus={showDatepicker} |
65 |
| - label={label} |
66 |
| - accessibilityLabel={label} |
67 |
| - accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT} |
68 |
| - onInputChange={setDate} |
69 |
| - value={value} |
70 |
| - defaultValue={defaultDateValue} |
71 |
| - placeholder={placeholder} |
72 |
| - errorText={errorText} |
73 |
| - containerStyles={containerStyles} |
74 |
| - disabled={disabled} |
75 |
| - onBlur={onBlur} |
76 |
| - /> |
77 |
| - ); |
| 70 | + if (_.isFunction(this.props.innerRef)) { |
| 71 | + this.props.innerRef(el); |
| 72 | + } |
| 73 | + }} |
| 74 | + onFocus={this.showDatepicker} |
| 75 | + label={this.props.label} |
| 76 | + accessibilityLabel={this.props.label} |
| 77 | + accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT} |
| 78 | + onInputChange={this.setDate} |
| 79 | + value={this.props.value} |
| 80 | + defaultValue={this.defaultValue} |
| 81 | + placeholder={this.props.placeholder} |
| 82 | + errorText={this.props.errorText} |
| 83 | + containerStyles={this.props.containerStyles} |
| 84 | + disabled={this.props.disabled} |
| 85 | + onBlur={this.props.onBlur} |
| 86 | + /> |
| 87 | + ); |
| 88 | + } |
78 | 89 | }
|
79 | 90 |
|
80 | 91 | DatePicker.propTypes = datePickerPropTypes;
|
81 | 92 | DatePicker.defaultProps = defaultProps;
|
82 |
| -DatePicker.displayName = 'DatePicker'; |
83 | 93 |
|
84 |
| -export default forwardRef((props, ref) => ( |
85 |
| - <DatePicker |
86 |
| - // eslint-disable-next-line react/jsx-props-no-spreading |
87 |
| - {...props} |
88 |
| - innerRef={ref} |
89 |
| - /> |
90 |
| -)); |
| 94 | +export default withWindowDimensions( |
| 95 | + React.forwardRef((props, ref) => ( |
| 96 | + <DatePicker |
| 97 | + // eslint-disable-next-line react/jsx-props-no-spreading |
| 98 | + {...props} |
| 99 | + innerRef={ref} |
| 100 | + /> |
| 101 | + )), |
| 102 | +); |
0 commit comments