Skip to content

Commit e6f8abf

Browse files
authored
Merge pull request #20864 from Expensify/srikar-refactorDateTime
Convert Date Picker to Functional Component
2 parents 563a791 + 8d7e0d7 commit e6f8abf

File tree

1 file changed

+51
-63
lines changed

1 file changed

+51
-63
lines changed

src/components/DatePicker/index.js

Lines changed: 51 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,90 @@
1-
import React from 'react';
21
import moment from 'moment';
2+
import React, {forwardRef, useEffect, useRef} from 'react';
33
import _ from 'underscore';
4-
import TextInput from '../TextInput';
54
import CONST from '../../CONST';
65
import * as Browser from '../../libs/Browser';
7-
import {propTypes, defaultProps} from './datepickerPropTypes';
8-
import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
6+
import TextInput from '../TextInput';
7+
import {defaultProps, propTypes} from './datepickerPropTypes';
98
import './styles.css';
109

1110
const datePickerPropTypes = {
1211
...propTypes,
13-
...windowDimensionsPropTypes,
1412
};
1513

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);
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) : '';
2217

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-
}
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]);
3324

3425
/**
3526
* Trigger the `onChange` handler when the user input has a complete date or is cleared
3627
* @param {String} text
3728
*/
38-
setDate(text) {
29+
const setDate = (text) => {
3930
if (!text) {
40-
this.props.onInputChange('');
31+
onInputChange('');
4132
return;
4233
}
4334

4435
const asMoment = moment(text, true);
4536
if (asMoment.isValid()) {
46-
this.props.onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING));
37+
onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING));
4738
}
48-
}
39+
};
4940

5041
/**
5142
* Pops the datepicker up when we focus this field. This only works on mWeb chrome
5243
* On mWeb chrome the user needs to tap on the field again in order to bring the datepicker. But our current styles
5344
* don't make this very obvious. To avoid confusion we open the datepicker when the user focuses the field
5445
*/
55-
showDatepicker() {
56-
if (!this.inputRef || !Browser.isMobileChrome()) {
46+
const showDatepicker = () => {
47+
if (!inputRef.current || !Browser.isMobileChrome()) {
5748
return;
5849
}
5950

60-
this.inputRef.click();
61-
}
51+
inputRef.current.click();
52+
};
6253

63-
render() {
64-
return (
65-
<TextInput
66-
forceActiveLabel
67-
ref={(el) => {
68-
this.inputRef = el;
54+
return (
55+
<TextInput
56+
forceActiveLabel
57+
ref={(el) => {
58+
inputRef.current = el;
6959

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-
}
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+
);
8978
}
9079

9180
DatePicker.propTypes = datePickerPropTypes;
9281
DatePicker.defaultProps = defaultProps;
82+
DatePicker.displayName = 'DatePicker';
9383

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-
);
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+
));

0 commit comments

Comments
 (0)