From 9bd1046acf2a6556ca406957cd95e0848f407833 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Mon, 14 Aug 2023 13:45:51 +0200 Subject: [PATCH] Refactor DatePicker component for ios Signed-off-by: Yauheni Pasiukevich --- src/components/DatePicker/index.ios.js | 220 ++++++++++++------------- 1 file changed, 102 insertions(+), 118 deletions(-) diff --git a/src/components/DatePicker/index.ios.js b/src/components/DatePicker/index.ios.js index 5d87636a9365..ef40aecb6f8c 100644 --- a/src/components/DatePicker/index.ios.js +++ b/src/components/DatePicker/index.ios.js @@ -1,147 +1,136 @@ -import React from 'react'; -// eslint-disable-next-line no-restricted-imports +import React, {useState, useRef, useCallback, useEffect} from 'react'; import {Button, View, Keyboard} from 'react-native'; import RNDatePicker from '@react-native-community/datetimepicker'; import moment from 'moment'; -import _ from 'underscore'; -import compose from '../../libs/compose'; +import isFunction from 'lodash/isFunction'; import TextInput from '../TextInput'; -import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import Popover from '../Popover'; import CONST from '../../CONST'; import styles from '../../styles/styles'; import themeColors from '../../styles/themes/default'; import {propTypes, defaultProps} from './datepickerPropTypes'; -import withKeyboardState, {keyboardStatePropTypes} from '../withKeyboardState'; +import useKeyboardState from '../../hooks/useKeyboardState'; +import useLocalize from '../../hooks/useLocalize'; -const datepickerPropTypes = { - ...propTypes, - ...withLocalizePropTypes, - ...keyboardStatePropTypes, -}; +function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLocale, minDate, maxDate, label, disabled, onBlur, placeholder, containerStyles, errorText}) { + const [isPickerVisible, setIsPickerVisible] = useState(false); + const [selectedDate, setSelectedDate] = useState(moment(value || defaultValue).toDate()); + const {isKeyboardShown} = useKeyboardState(); + const {translate} = useLocalize(); + const initialValue = useRef(null); + const inputRef = useRef(null); -class DatePicker extends React.Component { - constructor(props) { - super(props); - - this.state = { - isPickerVisible: false, - selectedDate: props.value || props.defaultValue ? moment(props.value || props.defaultValue).toDate() : new Date(), - }; - - this.showPicker = this.showPicker.bind(this); - this.reset = this.reset.bind(this); - this.selectDate = this.selectDate.bind(this); - this.updateLocalDate = this.updateLocalDate.bind(this); - } - - showPicker() { - this.initialValue = this.state.selectedDate; + const showPicker = useCallback(() => { + initialValue.current = selectedDate; // Opens the popover only after the keyboard is hidden to avoid a "blinking" effect where the keyboard was on iOS // See https://github.com/Expensify/App/issues/14084 for more context - if (!this.props.isKeyboardShown) { - this.setState({isPickerVisible: true}); + if (!isKeyboardShown) { + setIsPickerVisible(true); return; } + const listener = Keyboard.addListener('keyboardDidHide', () => { - this.setState({isPickerVisible: true}); + setIsPickerVisible(true); listener.remove(); }); Keyboard.dismiss(); - } + }, [isKeyboardShown, selectedDate]); + + useEffect(() => { + if (!isFunction(innerRef)) { + return; + } + + const input = inputRef.current; + + if (input && input.focus && isFunction(input.focus)) { + innerRef({...input, focus: showPicker}); + return; + } + + innerRef(input); + }, [innerRef, showPicker]); /** * Reset the date spinner to the initial value */ - reset() { - this.setState({selectedDate: this.initialValue}); - } + const reset = () => { + setSelectedDate(initialValue.current); + }; /** * Accept the current spinner changes, close the spinner and propagate the change - * to the parent component (props.onInputChange) + * to the parent component (onInputChange) */ - selectDate() { - this.setState({isPickerVisible: false}); - const asMoment = moment(this.state.selectedDate, true); - this.props.onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING)); - } + const selectDate = () => { + setIsPickerVisible(false); + const asMoment = moment(selectedDate, true); + onInputChange(asMoment.format(CONST.DATE.MOMENT_FORMAT_STRING)); + }; /** * @param {Event} event - * @param {Date} selectedDate + * @param {Date} date */ - updateLocalDate(event, selectedDate) { - this.setState({selectedDate}); - } + const updateLocalDate = (event, date) => { + setSelectedDate(date); + }; - render() { - const dateAsText = this.props.value || this.props.defaultValue ? moment(this.props.value || this.props.defaultValue).format(CONST.DATE.MOMENT_FORMAT_STRING) : ''; - return ( - <> - { - if (!_.isFunction(this.props.innerRef)) { - return; - } - if (el && el.focus && typeof el.focus === 'function') { - let inputRef = {...el}; - inputRef = {...inputRef, focus: this.showPicker}; - this.props.innerRef(inputRef); - return; - } + const dateAsText = value || defaultValue ? moment(value || defaultValue).format(CONST.DATE.MOMENT_FORMAT_STRING) : ''; - this.props.innerRef(el); - }} - /> - - -