From c7a0593914f9723a9945f7f4de61b09a637f0d70 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Mon, 11 Dec 2023 11:32:36 +0100 Subject: [PATCH 1/5] Move InputWrapper outside DatePicker --- src/components/DatePicker/index.js | 32 +++++++++++++----------------- src/stories/Form.stories.js | 3 ++- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js index 10a53dc25bbb..db72f4e26f88 100644 --- a/src/components/DatePicker/index.js +++ b/src/components/DatePicker/index.js @@ -1,9 +1,8 @@ import {setYear} from 'date-fns'; import _ from 'lodash'; import PropTypes from 'prop-types'; -import React, {useEffect, useState} from 'react'; +import React, {useState} from 'react'; import {View} from 'react-native'; -import InputWrapper from '@components/Form/InputWrapper'; import * as Expensicons from '@components/Icon/Expensicons'; import TextInput from '@components/TextInput'; import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '@components/TextInput/BaseTextInput/baseTextInputPropTypes'; @@ -33,6 +32,12 @@ const propTypes = { /** A maximum date of calendar to select */ maxDate: PropTypes.objectOf(Date), + /** A function that is passed by FormWrapper */ + onInputChange: PropTypes.func.isRequired, + + /** A function that is passed by FormWrapper */ + onTouched: PropTypes.func.isRequired, + ...withLocalizePropTypes, ...baseTextInputPropTypes, }; @@ -48,36 +53,27 @@ function DatePicker({containerStyles, defaultValue, disabled, errorText, inputID const styles = useThemeStyles(); const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined); - useEffect(() => { - if (selectedDate === value || _.isUndefined(value)) { - return; - } - setSelectedDate(value); - }, [selectedDate, value]); - - useEffect(() => { + const onSelected = (newValue) => { if (_.isFunction(onTouched)) { onTouched(); } if (_.isFunction(onInputChange)) { - onInputChange(selectedDate); + onInputChange(newValue); } - // To keep behavior from class component state update callback, we want to run effect only when the selected date is changed. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedDate]); + setSelectedDate(newValue); + }; return ( - diff --git a/src/stories/Form.stories.js b/src/stories/Form.stories.js index 6473b1074f17..dec57e4b41ee 100644 --- a/src/stories/Form.stories.js +++ b/src/stories/Form.stories.js @@ -69,7 +69,8 @@ function Template(args) { containerStyles={[styles.mt4]} hint="No PO box" /> - Date: Mon, 11 Dec 2023 13:57:36 +0100 Subject: [PATCH 2/5] Refactor DatePicker usages --- src/pages/EditRequestCreatedPage.js | 4 +++- src/pages/EnablePayments/AdditionalDetailsStep.js | 3 ++- src/pages/ReimbursementAccount/CompanyStep.js | 8 ++++++-- src/pages/ReimbursementAccount/IdentityForm.js | 4 ++-- src/pages/iou/MoneyRequestDatePage.js | 4 +++- src/pages/iou/request/step/IOURequestStepDate.js | 4 +++- .../settings/Profile/PersonalDetails/DateOfBirthPage.js | 4 +++- 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/pages/EditRequestCreatedPage.js b/src/pages/EditRequestCreatedPage.js index c2b05d9e6dfa..07de7abec942 100644 --- a/src/pages/EditRequestCreatedPage.js +++ b/src/pages/EditRequestCreatedPage.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; @@ -34,7 +35,8 @@ function EditRequestCreatedPage({defaultCreated, onSubmit}) { submitButtonText={translate('common.save')} enabledWhenOffline > - - ({value: key, label: translate(`companyStep.incorporationTypes.${key}`)}))} + items={_.map(_.keys(CONST.INCORPORATION_TYPES), (key) => ({ + value: key, + label: translate(`companyStep.incorporationTypes.${key}`), + }))} placeholder={{value: '', label: '-'}} defaultValue={getDefaultStateForField('incorporationType')} shouldSaveDraft /> - - props.onFieldChange({dob: value})} errorText={dobErrorText} minDate={minDate} maxDate={maxDate} diff --git a/src/pages/iou/MoneyRequestDatePage.js b/src/pages/iou/MoneyRequestDatePage.js index 8121bb381f32..a7ed27cf48b8 100644 --- a/src/pages/iou/MoneyRequestDatePage.js +++ b/src/pages/iou/MoneyRequestDatePage.js @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; @@ -99,7 +100,8 @@ function MoneyRequestDatePage({iou, route, selectedTab}) { submitButtonText={translate('common.save')} enabledWhenOffline > - - - Date: Thu, 14 Dec 2023 16:01:24 +0100 Subject: [PATCH 3/5] Wrap DatePicker with `React.forwardRef` --- src/components/DatePicker/index.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js index 0bc0399b8d82..5da3ac05cb2c 100644 --- a/src/components/DatePicker/index.js +++ b/src/components/DatePicker/index.js @@ -1,17 +1,21 @@ import {setYear} from 'date-fns'; import _ from 'lodash'; import PropTypes from 'prop-types'; -import React, {useState} from 'react'; +import React, {forwardRef, useState} from 'react'; import {View} from 'react-native'; import * as Expensicons from '@components/Icon/Expensicons'; +import refPropTypes from '@components/refPropTypes'; import TextInput from '@components/TextInput'; import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '@components/TextInput/BaseTextInput/baseTextInputPropTypes'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import CalendarPicker from './CalendarPicker'; const propTypes = { + /** React ref being forwarded to the DatePicker input */ + forwardedRef: refPropTypes, + /** * The datepicker supports any value that `new Date()` can parse. * `onInputChange` would always be called with a Date (or null) @@ -38,7 +42,6 @@ const propTypes = { /** A function that is passed by FormWrapper */ onTouched: PropTypes.func.isRequired, - ...withLocalizePropTypes, ...baseTextInputPropTypes, }; @@ -49,8 +52,9 @@ const datePickerDefaultProps = { value: undefined, }; -function DatePicker({containerStyles, defaultValue, disabled, errorText, inputID, isSmallScreenWidth, label, maxDate, minDate, onInputChange, onTouched, placeholder, translate, value}) { +function DatePicker({forwardedRef, containerStyles, defaultValue, disabled, errorText, inputID, isSmallScreenWidth, label, maxDate, minDate, onInputChange, onTouched, placeholder, value}) { const styles = useThemeStyles(); + const {translate} = useLocalize(); const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined); const onSelected = (newValue) => { @@ -67,6 +71,7 @@ function DatePicker({containerStyles, defaultValue, disabled, errorText, inputID ( + +)); + +DatePickerWithRef.displayName = 'DatePickerWithRef'; + +export default DatePickerWithRef; From 8c875110e815f23ca00c1f4e97f8685384d346c0 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Fri, 15 Dec 2023 13:05:43 +0100 Subject: [PATCH 4/5] Fix typo --- src/components/DatePicker/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js index 5da3ac05cb2c..a2ca930690ac 100644 --- a/src/components/DatePicker/index.js +++ b/src/components/DatePicker/index.js @@ -105,7 +105,7 @@ DatePicker.defaultProps = datePickerDefaultProps; DatePicker.displayName = 'DatePicker'; const DatePickerWithRef = forwardRef((props, ref) => ( - Date: Mon, 18 Dec 2023 11:18:32 +0100 Subject: [PATCH 5/5] Remove unused prop --- src/pages/ReimbursementAccount/IdentityForm.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 9e61c3db9b95..27d12b2f9d75 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -14,9 +14,6 @@ const propTypes = { /** Style for wrapping View */ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), - /** Callback fired when a field changes. Passes args as {[fieldName]: val} */ - onFieldChange: PropTypes.func, - /** Form values */ values: PropTypes.shape({ /** First name field */ @@ -127,7 +124,6 @@ const defaultProps = { ssnLast4: '', }, shouldSaveDraft: false, - onFieldChange: () => {}, }; function IdentityForm(props) { @@ -152,7 +148,6 @@ function IdentityForm(props) { role={CONST.ROLE.PRESENTATION} value={props.values.firstName} defaultValue={props.defaultValues.firstName} - onChangeText={(value) => props.onFieldChange({firstName: value})} errorText={props.errors.firstName ? props.translate('bankAccount.error.firstName') : ''} /> @@ -166,7 +161,6 @@ function IdentityForm(props) { role={CONST.ROLE.PRESENTATION} value={props.values.lastName} defaultValue={props.defaultValues.lastName} - onChangeText={(value) => props.onFieldChange({lastName: value})} errorText={props.errors.lastName ? props.translate('bankAccount.error.lastName') : ''} /> @@ -193,7 +187,6 @@ function IdentityForm(props) { containerStyles={[styles.mt4]} inputMode={CONST.INPUT_MODE.NUMERIC} defaultValue={props.defaultValues.ssnLast4} - onChangeText={(value) => props.onFieldChange({ssnLast4: value})} errorText={props.errors.ssnLast4 ? props.translate('bankAccount.error.ssnLast4') : ''} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.SSN} /> @@ -205,7 +198,6 @@ function IdentityForm(props) { values={_.omit(props.values, identityFormInputKeys)} defaultValues={_.omit(props.defaultValues, identityFormInputKeys)} errors={props.errors} - onFieldChange={props.onFieldChange} /> );