Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form migration NewDatePicker, DateOfBirthPage, EditRequestCreatedPage #29098

2 changes: 1 addition & 1 deletion src/components/Form/FormProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function FormProvider({validate, shouldValidateOnBlur, shouldValidateOnChange, c

const onValidate = useCallback(
(values) => {
const validateErrors = validate(values);
const validateErrors = validate(values) || {};
setErrors(validateErrors);
return validateErrors;
},
Expand Down
108 changes: 52 additions & 56 deletions src/components/NewDatePicker/index.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not have used InputWrapper here as it "hides" the NewDataPicker's changes from the FormProvider. Instead we should have used InputWrapper to wrap the whole component and not just the TextInput. More info: #31401 (comment). (Coming from #31612)

Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import moment from 'moment';
import PropTypes from 'prop-types';
import _ from 'lodash';
import TextInput from '../TextInput';
import CONST from '../../CONST';
import styles from '../../styles/styles';
import * as Expensicons from '../Icon/Expensicons';
import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '../TextInput/baseTextInputPropTypes';
import {defaultProps as defaultBaseTextInputPropTypes, propTypes as baseTextInputPropTypes} from '../TextInput/baseTextInputPropTypes';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
import CalendarPicker from './CalendarPicker';
import InputWrapper from '../Form/InputWrapper';

const propTypes = {
/**
Expand All @@ -23,6 +25,8 @@ const propTypes = {
*/
defaultValue: PropTypes.string,

inputID: PropTypes.string.isRequired,

/** A minimum date of calendar to select */
minDate: PropTypes.objectOf(Date),

Expand All @@ -40,66 +44,58 @@ const datePickerDefaultProps = {
value: undefined,
};

class NewDatePicker extends React.Component {
constructor(props) {
super(props);

this.state = {
selectedDate: props.value || props.defaultValue || undefined,
};
function NewDatePicker({containerStyles, defaultValue, disabled, errorText, inputID, isSmallScreenWidth, label, maxDate, minDate, onInputChange, onTouched, placeholder, translate, value}) {
const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined);

this.setDate = this.setDate.bind(this);
}

componentDidUpdate(prevProps) {
if (prevProps.value === this.props.value) {
useEffect(() => {
if (selectedDate === value || _.isUndefined(value)) {
return;
}
this.setDate(this.props.value);
}
setSelectedDate(value);
}, [selectedDate, value]);

/**
* Trigger the `onInputChange` handler when the user input has a complete date or is cleared
* @param {string} selectedDate
*/
setDate(selectedDate) {
this.setState({selectedDate}, () => {
this.props.onTouched();
this.props.onInputChange(selectedDate);
});
}
useEffect(() => {
if (_.isFunction(onTouched)) {
onTouched();
}
if (_.isFunction(onInputChange)) {
onInputChange(selectedDate);
}
// 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]);

render() {
return (
<View style={styles.datePickerRoot}>
<View style={[this.props.isSmallScreenWidth ? styles.flex2 : {}, styles.pointerEventsNone]}>
<TextInput
forceActiveLabel
icon={Expensicons.Calendar}
label={this.props.label}
accessibilityLabel={this.props.label}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
value={this.props.value || ''}
placeholder={this.props.placeholder || this.props.translate('common.dateFormat')}
errorText={this.props.errorText}
containerStyles={this.props.containerStyles}
textInputContainerStyles={[styles.borderColorFocus]}
inputStyle={[styles.pointerEventsNone]}
disabled={this.props.disabled}
editable={false}
/>
</View>
<View style={[styles.datePickerPopover, styles.border]}>
<CalendarPicker
minDate={this.props.minDate}
maxDate={this.props.maxDate}
value={this.state.selectedDate}
onSelected={this.setDate}
/>
</View>
return (
<View style={styles.datePickerRoot}>
<View style={[isSmallScreenWidth ? styles.flex2 : {}, styles.pointerEventsNone]}>
<InputWrapper
InputComponent={TextInput}
inputID={inputID}
forceActiveLabel
icon={Expensicons.Calendar}
label={label}
accessibilityLabel={label}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
value={value || selectedDate || ''}
placeholder={placeholder || translate('common.dateFormat')}
errorText={errorText}
containerStyles={containerStyles}
textInputContainerStyles={[styles.borderColorFocus]}
inputStyle={[styles.pointerEventsNone]}
disabled={disabled}
editable={false}
/>
</View>
<View style={[styles.datePickerPopover, styles.border]}>
<CalendarPicker
minDate={minDate}
maxDate={maxDate}
value={selectedDate}
onSelected={setSelectedDate}
/>
</View>
);
}
</View>
);
}

NewDatePicker.propTypes = propTypes;
Expand Down
6 changes: 3 additions & 3 deletions src/pages/EditRequestCreatedPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
import ScreenWrapper from '../components/ScreenWrapper';
import HeaderWithBackButton from '../components/HeaderWithBackButton';
import Form from '../components/Form';
import ONYXKEYS from '../ONYXKEYS';
import styles from '../styles/styles';
import useLocalize from '../hooks/useLocalize';
import NewDatePicker from '../components/NewDatePicker';
import FormProvider from '../components/Form/FormProvider';

const propTypes = {
/** Transaction defailt created value */
Expand All @@ -26,7 +26,7 @@ function EditRequestCreatedPage({defaultCreated, onSubmit}) {
testID={EditRequestCreatedPage.displayName}
>
<HeaderWithBackButton title={translate('common.date')} />
<Form
<FormProvider
style={[styles.flexGrow1, styles.ph5]}
formID={ONYXKEYS.FORMS.MONEY_REQUEST_DATE_FORM}
onSubmit={onSubmit}
Expand All @@ -39,7 +39,7 @@ function EditRequestCreatedPage({defaultCreated, onSubmit}) {
defaultValue={defaultCreated}
maxDate={new Date()}
/>
</Form>
</FormProvider>
</ScreenWrapper>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/pages/iou/MoneyRequestDatePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import _ from 'underscore';
import lodashGet from 'lodash/get';
import ScreenWrapper from '../../components/ScreenWrapper';
import HeaderWithBackButton from '../../components/HeaderWithBackButton';
import Form from '../../components/Form';
import ONYXKEYS from '../../ONYXKEYS';
import styles from '../../styles/styles';
import Navigation from '../../libs/Navigation/Navigation';
Expand All @@ -16,6 +15,7 @@ import NewDatePicker from '../../components/NewDatePicker';
import useLocalize from '../../hooks/useLocalize';
import CONST from '../../CONST';
import {iouPropTypes, iouDefaultProps} from './propTypes';
import FormProvider from '../../components/Form/FormProvider';

const propTypes = {
/** Onyx Props */
Expand Down Expand Up @@ -91,7 +91,7 @@ function MoneyRequestDatePage({iou, route, selectedTab}) {
title={translate('common.date')}
onBackButtonPress={() => navigateBack()}
/>
<Form
<FormProvider
style={[styles.flexGrow1, styles.ph5]}
formID={ONYXKEYS.FORMS.MONEY_REQUEST_DATE_FORM}
onSubmit={(value) => updateDate(value)}
Expand All @@ -104,7 +104,7 @@ function MoneyRequestDatePage({iou, route, selectedTab}) {
defaultValue={iou.created}
maxDate={new Date()}
/>
</Form>
</FormProvider>
</ScreenWrapper>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {subYears} from 'date-fns';
import CONST from '../../../../CONST';
import ONYXKEYS from '../../../../ONYXKEYS';
import ROUTES from '../../../../ROUTES';
import Form from '../../../../components/Form';
import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
import NewDatePicker from '../../../../components/NewDatePicker';
import ScreenWrapper from '../../../../components/ScreenWrapper';
Expand All @@ -18,6 +17,7 @@ import compose from '../../../../libs/compose';
import styles from '../../../../styles/styles';
import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
import FormProvider from '../../../../components/Form/FormProvider';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -72,7 +72,7 @@ function DateOfBirthPage({translate, privatePersonalDetails}) {
{isLoadingPersonalDetails ? (
<FullscreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
) : (
<Form
<FormProvider
style={[styles.flexGrow1, styles.ph5]}
formID={ONYXKEYS.FORMS.DATE_OF_BIRTH_FORM}
validate={validate}
Expand All @@ -87,7 +87,7 @@ function DateOfBirthPage({translate, privatePersonalDetails}) {
minDate={subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE)}
maxDate={subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE)}
/>
</Form>
</FormProvider>
)}
</ScreenWrapper>
);
Expand Down
Loading