diff --git a/src/ROUTES.js b/src/ROUTES.js
index a95a68964998..b4ca019709b0 100644
--- a/src/ROUTES.js
+++ b/src/ROUTES.js
@@ -70,8 +70,6 @@ export default {
getReportShareCodeRoute: (reportID) => `r/${reportID}/details/shareCode`,
REPORT_ATTACHMENTS: 'r/:reportID/attachment',
getReportAttachmentRoute: (reportID, source) => `r/${reportID}/attachment?source=${encodeURI(source)}`,
- SELECT_YEAR: 'select-year',
- getYearSelectionRoute: (minYear, maxYear, currYear, backTo) => `select-year?min=${minYear}&max=${maxYear}&year=${currYear}&backTo=${backTo}`,
/** This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated */
CONCIERGE: 'concierge',
diff --git a/src/components/CalendarPicker/calendarPickerPropTypes.js b/src/components/CalendarPicker/calendarPickerPropTypes.js
deleted file mode 100644
index 8a2e62d302a7..000000000000
--- a/src/components/CalendarPicker/calendarPickerPropTypes.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import PropTypes from 'prop-types';
-import moment from 'moment';
-import CONST from '../../CONST';
-
-const propTypes = {
- /** An initial value of date string */
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
-
- /** A minimum date (oldest) allowed to select */
- minDate: PropTypes.objectOf(Date),
-
- /** A maximum date (earliest) allowed to select */
- maxDate: PropTypes.objectOf(Date),
-
- /** Default year to be set in the calendar picker. Used with navigation to set the correct year after going back to the view with calendar */
- selectedYear: PropTypes.string,
-
- /** Default month to be set in the calendar picker. Used to keep last selected month after going back to the view with calendar */
- selectedMonth: PropTypes.number,
-
- /** A function that is called when the date changed inside the calendar component */
- onChanged: PropTypes.func,
-
- /** A function called when the date is selected */
- onSelected: PropTypes.func,
-
- /** A function called when the year picker is opened */
- onYearPickerOpen: PropTypes.func,
-};
-
-const defaultProps = {
- value: new Date(),
- minDate: moment().year(CONST.CALENDAR_PICKER.MIN_YEAR).toDate(),
- maxDate: moment().year(CONST.CALENDAR_PICKER.MAX_YEAR).toDate(),
- selectedYear: null,
- selectedMonth: null,
- onChanged: () => {},
- onSelected: () => {},
- onYearPickerOpen: () => {},
-};
-
-export {propTypes, defaultProps};
diff --git a/src/components/Modal/modalPropTypes.js b/src/components/Modal/modalPropTypes.js
index 820340f9d93e..58de5a6c57ca 100644
--- a/src/components/Modal/modalPropTypes.js
+++ b/src/components/Modal/modalPropTypes.js
@@ -58,6 +58,14 @@ const propTypes = {
/** Whether the modal should avoid the keyboard */
avoidKeyboard: PropTypes.bool,
+ /**
+ * Whether the modal should hide its content while animating. On iOS, set to true
+ * if `useNativeDriver` is also true, to avoid flashes in the UI.
+ *
+ * See: https://github.com/react-native-modal/react-native-modal/pull/116
+ * */
+ hideModalContentWhileAnimating: PropTypes.bool,
+
...windowDimensionsPropTypes,
};
@@ -75,6 +83,7 @@ const defaultProps = {
innerContainerStyle: {},
statusBarTranslucent: true,
avoidKeyboard: false,
+ hideModalContentWhileAnimating: false,
};
export {propTypes, defaultProps};
diff --git a/src/components/CalendarPicker/ArrowIcon.js b/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
similarity index 78%
rename from src/components/CalendarPicker/ArrowIcon.js
rename to src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
index 75312c894524..6d5757323480 100644
--- a/src/components/CalendarPicker/ArrowIcon.js
+++ b/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
@@ -1,11 +1,11 @@
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import * as Expensicons from '../Icon/Expensicons';
-import * as StyleUtils from '../../styles/StyleUtils';
-import Icon from '../Icon';
-import CONST from '../../CONST';
+import styles from '../../../styles/styles';
+import * as Expensicons from '../../Icon/Expensicons';
+import * as StyleUtils from '../../../styles/StyleUtils';
+import Icon from '../../Icon';
+import CONST from '../../../CONST';
const propTypes = {
/** Specifies if the arrow icon should be disabled or not. */
diff --git a/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
new file mode 100644
index 000000000000..24e22fb1f746
--- /dev/null
+++ b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
@@ -0,0 +1,85 @@
+import React, {useEffect, useMemo, useState} from 'react';
+import PropTypes from 'prop-types';
+import _ from 'underscore';
+import HeaderWithBackButton from '../../HeaderWithBackButton';
+import CONST from '../../../CONST';
+import SelectionListRadio from '../../SelectionListRadio';
+import Modal from '../../Modal';
+import {radioListItemPropTypes} from '../../SelectionListRadio/selectionListRadioPropTypes';
+import useLocalize from '../../../hooks/useLocalize';
+
+const propTypes = {
+ /** Whether the modal is visible */
+ isVisible: PropTypes.bool.isRequired,
+
+ /** The list of years to render */
+ years: PropTypes.arrayOf(PropTypes.shape(radioListItemPropTypes)).isRequired,
+
+ /** Currently selected year */
+ currentYear: PropTypes.number,
+
+ /** Function to call when the user selects a year */
+ onYearChange: PropTypes.func,
+
+ /** Function to call when the user closes the year picker */
+ onClose: PropTypes.func,
+};
+
+const defaultProps = {
+ currentYear: new Date().getFullYear(),
+ onYearChange: () => {},
+ onClose: () => {},
+};
+
+function YearPickerModal(props) {
+ const {translate} = useLocalize();
+ const [searchText, setSearchText] = useState('');
+ const {sections, headerMessage} = useMemo(() => {
+ const yearsList = searchText === '' ? props.years : _.filter(props.years, (year) => year.text.includes(searchText));
+ return {
+ headerMessage: !yearsList.length ? translate('common.noResultsFound') : '',
+ sections: [{data: yearsList, indexOffset: 0}],
+ };
+ }, [props.years, searchText, translate]);
+
+ useEffect(() => {
+ if (props.isVisible) {
+ return;
+ }
+ setSearchText('');
+ }, [props.isVisible]);
+
+ return (
+
+
+ setSearchText(text.replace(CONST.REGEX.NON_NUMERIC, '').trim())}
+ keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
+ headerMessage={headerMessage}
+ sections={sections}
+ onSelectRow={(option) => props.onYearChange(option.value)}
+ initiallyFocusedOptionKey={props.currentYear.toString()}
+ />
+
+ );
+}
+
+YearPickerModal.propTypes = propTypes;
+YearPickerModal.defaultProps = defaultProps;
+YearPickerModal.displayName = 'YearPickerModal';
+
+export default YearPickerModal;
diff --git a/src/components/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
similarity index 98%
rename from src/components/CalendarPicker/generateMonthMatrix.js
rename to src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
index d58e3c0521d2..62a1a50b3297 100644
--- a/src/components/CalendarPicker/generateMonthMatrix.js
+++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
@@ -1,5 +1,5 @@
import moment from 'moment';
-import CONST from '../../CONST';
+import CONST from '../../../CONST';
/**
* Generates a matrix representation of a month's calendar given the year and month.
diff --git a/src/components/CalendarPicker/index.js b/src/components/NewDatePicker/CalendarPicker/index.js
similarity index 54%
rename from src/components/CalendarPicker/index.js
rename to src/components/NewDatePicker/CalendarPicker/index.js
index f8dc9dc5b330..fe0c36d32e41 100644
--- a/src/components/CalendarPicker/index.js
+++ b/src/components/NewDatePicker/CalendarPicker/index.js
@@ -2,97 +2,94 @@ import _ from 'underscore';
import React from 'react';
import {View} from 'react-native';
import moment from 'moment';
+import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
-import Text from '../Text';
+import Text from '../../Text';
+import YearPickerModal from './YearPickerModal';
import ArrowIcon from './ArrowIcon';
-import styles from '../../styles/styles';
-import {propTypes as calendarPickerPropType, defaultProps as defaultCalendarPickerPropType} from './calendarPickerPropTypes';
+import styles from '../../../styles/styles';
import generateMonthMatrix from './generateMonthMatrix';
-import withLocalize from '../withLocalize';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import CONST from '../../CONST';
-import getButtonState from '../../libs/getButtonState';
-import * as StyleUtils from '../../styles/StyleUtils';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
+import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
+import CONST from '../../../CONST';
+import getButtonState from '../../../libs/getButtonState';
+import * as StyleUtils from '../../../styles/StyleUtils';
+import PressableWithFeedback from '../../Pressable/PressableWithFeedback';
+import PressableWithoutFeedback from '../../Pressable/PressableWithoutFeedback';
+
+const propTypes = {
+ /** An initial value of date string */
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
+
+ /** A minimum date (oldest) allowed to select */
+ minDate: PropTypes.instanceOf(Date),
+
+ /** A maximum date (earliest) allowed to select */
+ maxDate: PropTypes.instanceOf(Date),
+
+ /** A function called when the date is selected */
+ onSelected: PropTypes.func,
+
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ value: new Date(),
+ minDate: moment().year(CONST.CALENDAR_PICKER.MIN_YEAR).toDate(),
+ maxDate: moment().year(CONST.CALENDAR_PICKER.MAX_YEAR).toDate(),
+ onSelected: () => {},
+};
class CalendarPicker extends React.PureComponent {
constructor(props) {
super(props);
- let currentSelection = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING);
- let currentDateView = currentSelection.toDate();
-
- if (props.selectedYear) {
- currentDateView = moment(currentDateView).set('year', props.selectedYear).toDate();
- }
- if (props.selectedMonth != null) {
- currentDateView = moment(currentDateView).set('month', props.selectedMonth).toDate();
+ if (props.minDate >= props.maxDate) {
+ throw new Error('Minimum date cannot be greater than the maximum date.');
}
+
+ let currentDateView = moment(props.value, CONST.DATE.MOMENT_FORMAT_STRING).toDate();
if (props.maxDate < currentDateView) {
currentDateView = props.maxDate;
- currentSelection = moment(props.maxDate);
} else if (props.minDate > currentDateView) {
currentDateView = props.minDate;
- currentSelection = moment(props.minDate);
}
+ const minYear = moment(this.props.minDate).year();
+ const maxYear = moment(this.props.maxDate).year();
+
this.state = {
currentDateView,
- selectedYear: currentSelection.get('year').toString(),
- selectedMonth: this.getNumberStringWithLeadingZero(currentSelection.get('month') + 1),
- selectedDay: this.getNumberStringWithLeadingZero(currentSelection.get('date')),
+ isYearPickerVisible: false,
+ years: _.map(
+ Array.from({length: maxYear - minYear + 1}, (v, i) => i + minYear),
+ (value) => ({
+ text: value.toString(),
+ value,
+ keyForList: value.toString(),
+ isSelected: value === currentDateView.getFullYear(),
+ }),
+ ),
};
this.moveToPrevMonth = this.moveToPrevMonth.bind(this);
this.moveToNextMonth = this.moveToNextMonth.bind(this);
- this.onYearPickerPressed = this.onYearPickerPressed.bind(this);
this.onDayPressed = this.onDayPressed.bind(this);
+ this.onYearSelected = this.onYearSelected.bind(this);
}
- componentDidMount() {
- if (this.props.minDate <= this.props.maxDate) {
- return;
- }
- throw new Error('Minimum date cannot be greater than the maximum date.');
- }
-
- componentDidUpdate(prevProps, prevState) {
- // if the selectedYear prop or state has changed, update the currentDateView state with the new year value
- if (this.props.selectedYear === prevProps.selectedYear && prevState.selectedYear === this.state.selectedYear) {
- return;
- }
-
- // If we changed the prop for selectedYear, update the state to match it, otherwise use the state value
- const newSelectedYear = this.props.selectedYear !== prevProps.selectedYear ? this.props.selectedYear : this.state.selectedYear;
-
- this.setState(
- (prev) => {
- const newMomentDate = moment(prev.currentDateView).set('year', newSelectedYear);
-
- return {
- selectedYear: newSelectedYear,
- currentDateView: this.clampDate(newMomentDate.toDate()),
- };
- },
- () => {
- this.props.onSelected(this.getSelectedDateString());
- },
- );
- }
-
- /**
- * Handles the user pressing the year picker button.
- * Opens the year selection screen with the minimum and maximum year range
- * based on the props, the current year based on the state, and the active route.
- */
- onYearPickerPressed() {
- const minYear = moment(this.props.minDate).year();
- const maxYear = moment(this.props.maxDate).year();
- const currentYear = parseInt(this.state.selectedYear, 10);
- Navigation.navigate(ROUTES.getYearSelectionRoute(minYear, maxYear, currentYear, Navigation.getActiveRoute()));
- this.props.onYearPickerOpen(this.state.currentDateView);
+ onYearSelected(year) {
+ this.setState((prev) => {
+ const newCurrentDateView = moment(prev.currentDateView).set('year', year).toDate();
+
+ return {
+ currentDateView: newCurrentDateView,
+ isYearPickerVisible: false,
+ years: _.map(prev.years, (item) => ({
+ ...item,
+ isSelected: item.value === newCurrentDateView.getFullYear(),
+ })),
+ };
+ });
}
/**
@@ -101,101 +98,25 @@ class CalendarPicker extends React.PureComponent {
*/
onDayPressed(day) {
this.setState(
- (prev) => {
- const momentDate = moment(prev.currentDateView).date(day);
-
- return {
- selectedDay: this.getNumberStringWithLeadingZero(day),
- currentDateView: this.clampDate(momentDate.toDate()),
- };
- },
- () => {
- this.props.onSelected(this.getSelectedDateString());
- },
+ (prev) => ({
+ currentDateView: moment(prev.currentDateView).set('date', day).toDate(),
+ }),
+ () => this.props.onSelected(moment(this.state.currentDateView).format('YYYY-MM-DD')),
);
}
- /**
- * Gets the date string build from state values of selected year, month and day.
- * @returns {string} - Date string in the 'YYYY-MM-DD' format.
- */
- getSelectedDateString() {
- // can't use moment.format() method here because it won't allow incorrect dates
- return `${this.state.selectedYear}-${this.state.selectedMonth}-${this.state.selectedDay}`;
- }
-
- /**
- * Returns the string converted from the given number. If the number is lower than 10,
- * it will add zero at the beginning of the string.
- * @param {Number} number - The number to be converted.
- * @returns {string} - Converted string prefixed by zero if necessary.
- */
- getNumberStringWithLeadingZero(number) {
- return `${number < 10 ? `0${number}` : number}`;
- }
-
- /**
- * Gives the new version of the state object,
- * changing both selected month and year based on the given moment date.
- * @param {moment.Moment} momentDate - Moment date object.
- * @returns {{currentDateView: Date, selectedMonth: string, selectedYear: string}} - The new version of the state.
- */
- getMonthState(momentDate) {
- const clampedDate = this.clampDate(momentDate.toDate());
- const month = clampedDate.getMonth() + 1;
-
- return {
- selectedMonth: this.getNumberStringWithLeadingZero(month),
- selectedYear: clampedDate.getFullYear().toString(), // year might have changed too
- currentDateView: clampedDate,
- };
- }
-
/**
* Handles the user pressing the previous month arrow of the calendar picker.
*/
moveToPrevMonth() {
- this.setState(
- (prev) => {
- const momentDate = moment(prev.currentDateView).subtract(1, 'M');
-
- return this.getMonthState(momentDate);
- },
- () => {
- this.props.onSelected(this.getSelectedDateString());
- },
- );
+ this.setState((prev) => ({currentDateView: moment(prev.currentDateView).subtract(1, 'months').toDate()}));
}
/**
* Handles the user pressing the next month arrow of the calendar picker.
*/
moveToNextMonth() {
- this.setState(
- (prev) => {
- const momentDate = moment(prev.currentDateView).add(1, 'M');
-
- return this.getMonthState(momentDate);
- },
- () => {
- this.props.onSelected(this.getSelectedDateString());
- },
- );
- }
-
- /**
- * Checks whether the given date is in the min/max date range and returns the limit value if not.
- * @param {Date} date - The date object to check.
- * @returns {Date} - The date that is within the min/max date range.
- */
- clampDate(date) {
- if (this.props.maxDate < date) {
- return this.props.maxDate;
- }
- if (this.props.minDate > date) {
- return this.props.minDate;
- }
- return date;
+ this.setState((prev) => ({currentDateView: moment(prev.currentDateView).add(1, 'months').toDate()}));
}
render() {
@@ -204,17 +125,18 @@ class CalendarPicker extends React.PureComponent {
const currentMonthView = this.state.currentDateView.getMonth();
const currentYearView = this.state.currentDateView.getFullYear();
const calendarDaysMatrix = generateMonthMatrix(currentYearView, currentMonthView);
- const hasAvailableDatesNextMonth = moment(this.props.maxDate).endOf('month').startOf('day') > moment(this.state.currentDateView).add(1, 'M');
- const hasAvailableDatesPrevMonth = moment(this.props.minDate).startOf('day') < moment(this.state.currentDateView).subtract(1, 'M').endOf('month');
+ const hasAvailableDatesNextMonth = moment(this.props.maxDate).endOf('month').startOf('day') > moment(this.state.currentDateView).add(1, 'months');
+ const hasAvailableDatesPrevMonth = moment(this.props.minDate).startOf('day') < moment(this.state.currentDateView).subtract(1, 'months').endOf('month');
return (
this.setState({isYearPickerVisible: true})}
style={[styles.alignItemsCenter, styles.flexRow, styles.flex1, styles.justifyContentStart]}
wrapperStyle={[styles.alignItemsCenter]}
hoverDimmingValue={1}
+ testID="currentYearButton"
accessibilityLabel={this.props.translate('common.currentYear')}
>
))}
+ this.setState({isYearPickerVisible: false})}
+ />
);
}
}
-CalendarPicker.propTypes = calendarPickerPropType;
-CalendarPicker.defaultProps = defaultCalendarPickerPropType;
+CalendarPicker.propTypes = propTypes;
+CalendarPicker.defaultProps = defaultProps;
export default withLocalize(CalendarPicker);
diff --git a/src/components/NewDatePicker/datePickerPropTypes.js b/src/components/NewDatePicker/datePickerPropTypes.js
deleted file mode 100644
index b08371030fc0..000000000000
--- a/src/components/NewDatePicker/datePickerPropTypes.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import PropTypes from 'prop-types';
-import moment from 'moment';
-import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '../TextInput/baseTextInputPropTypes';
-import CONST from '../../CONST';
-
-const propTypes = {
- ...baseTextInputPropTypes,
-
- /**
- * The datepicker supports any value that `moment` can parse.
- * `onInputChange` would always be called with a Date (or null)
- */
- value: PropTypes.string,
-
- /**
- * The datepicker supports any defaultValue that `moment` can parse.
- * `onInputChange` would always be called with a Date (or null)
- */
- defaultValue: PropTypes.string,
-
- /** A minimum date of calendar to select */
- minDate: PropTypes.objectOf(Date),
-
- /** A maximum date of calendar to select */
- maxDate: PropTypes.objectOf(Date),
-
- /** Default year to be set in the calendar picker */
- selectedYear: PropTypes.string,
-};
-
-const defaultProps = {
- ...defaultBaseTextInputPropTypes,
- minDate: moment().year(CONST.CALENDAR_PICKER.MIN_YEAR).toDate(),
- maxDate: moment().year(CONST.CALENDAR_PICKER.MAX_YEAR).toDate(),
- value: undefined,
-};
-
-export {propTypes, defaultProps};
diff --git a/src/components/NewDatePicker/index.js b/src/components/NewDatePicker/index.js
index 5ab35aefb563..b5dad7992bfb 100644
--- a/src/components/NewDatePicker/index.js
+++ b/src/components/NewDatePicker/index.js
@@ -1,21 +1,43 @@
import React from 'react';
import {View} from 'react-native';
import moment from 'moment';
+import PropTypes from 'prop-types';
import TextInput from '../TextInput';
-import CalendarPicker from '../CalendarPicker';
import CONST from '../../CONST';
import styles from '../../styles/styles';
import * as Expensicons from '../Icon/Expensicons';
-import {propTypes as datePickerPropTypes, defaultProps as defaultDatePickerProps} from './datePickerPropTypes';
+import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '../TextInput/baseTextInputPropTypes';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
+import CalendarPicker from './CalendarPicker';
const propTypes = {
+ /**
+ * The datepicker supports any value that `moment` can parse.
+ * `onInputChange` would always be called with a Date (or null)
+ */
+ value: PropTypes.string,
+
+ /**
+ * The datepicker supports any defaultValue that `moment` can parse.
+ * `onInputChange` would always be called with a Date (or null)
+ */
+ defaultValue: PropTypes.string,
+
+ /** A minimum date of calendar to select */
+ minDate: PropTypes.objectOf(Date),
+
+ /** A maximum date of calendar to select */
+ maxDate: PropTypes.objectOf(Date),
+
...withLocalizePropTypes,
- ...datePickerPropTypes,
+ ...baseTextInputPropTypes,
};
const datePickerDefaultProps = {
- ...defaultDatePickerProps,
+ ...defaultBaseTextInputPropTypes,
+ minDate: moment().year(CONST.CALENDAR_PICKER.MIN_YEAR).toDate(),
+ maxDate: moment().year(CONST.CALENDAR_PICKER.MAX_YEAR).toDate(),
+ value: undefined,
};
class NewDatePicker extends React.Component {
@@ -23,12 +45,10 @@ class NewDatePicker extends React.Component {
super(props);
this.state = {
- selectedMonth: null,
selectedDate: props.value || props.defaultValue || undefined,
};
this.setDate = this.setDate.bind(this);
- this.setCurrentSelectedMonth = this.setCurrentSelectedMonth.bind(this);
// We're using uncontrolled input otherwise it won't be possible to
// raise change events with a date value - each change will produce a date
@@ -36,15 +56,6 @@ class NewDatePicker extends React.Component {
this.defaultValue = props.defaultValue ? moment(props.defaultValue).format(CONST.DATE.MOMENT_FORMAT_STRING) : '';
}
- /**
- * Updates selected month when year picker is opened.
- * This is used to keep the last visible month in the calendar when going back from year picker screen.
- * @param {Date} currentDateView
- */
- setCurrentSelectedMonth(currentDateView) {
- this.setState({selectedMonth: currentDateView.getMonth()});
- }
-
/**
* Trigger the `onInputChange` handler when the user input has a complete date or is cleared
* @param {string} selectedDate
@@ -81,9 +92,6 @@ class NewDatePicker extends React.Component {
maxDate={this.props.maxDate}
value={this.state.selectedDate}
onSelected={this.setDate}
- selectedMonth={this.state.selectedMonth}
- selectedYear={this.props.selectedYear}
- onYearPickerOpen={this.setCurrentSelectedMonth}
/>
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 518ff33b0ad4..b64d66782521 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -619,13 +619,6 @@ const SettingsModalStackNavigator = createModalStackNavigator([
},
name: 'GetAssistance',
},
- {
- getComponent: () => {
- const YearPickerPage = require('../../../pages/YearPickerPage').default;
- return YearPickerPage;
- },
- name: 'YearPicker_Root',
- },
{
getComponent: () => {
const SettingsTwoFactorAuthIsEnabled = require('../../../pages/settings/Security/TwoFactorAuth/IsEnabledPage').default;
@@ -703,16 +696,6 @@ const WalletStatementStackNavigator = createModalStackNavigator([
},
]);
-const YearPickerStackNavigator = createModalStackNavigator([
- {
- getComponent: () => {
- const YearPickerPage = require('../../../pages/YearPickerPage').default;
- return YearPickerPage;
- },
- name: 'YearPicker_Root',
- },
-]);
-
const FlagCommentStackNavigator = createModalStackNavigator([
{
getComponent: () => {
@@ -752,7 +735,6 @@ export {
AddPersonalBankAccountModalStackNavigator,
ReimbursementAccountModalStackNavigator,
WalletStatementStackNavigator,
- YearPickerStackNavigator,
FlagCommentStackNavigator,
EditRequestStackNavigator,
};
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
index a04e9bfc10ec..7d6d4cb2709c 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
@@ -85,10 +85,6 @@ function RigthModalNavigator() {
name="Wallet_Statement"
component={ModalStackNavigators.WalletStatementStackNavigator}
/>
-
i + minYear),
- (value) => ({
- text: value.toString(),
- value,
- keyForList: value.toString(),
- isSelected: value === currentYear,
- }),
- );
-
- this.updateYearOfBirth = this.updateSelectedYear.bind(this);
- this.filterYearList = this.filterYearList.bind(this);
-
- this.state = {
- inputText: '',
- yearOptions: this.yearList,
- };
- }
-
- /**
- * Function called on selection of the year, to take user back to the previous screen
- *
- * @param {String} selectedYear
- */
- updateSelectedYear(selectedYear) {
- // We have to navigate using concatenation here as it is not possible to pass a function as a route param
- const routes = lodashGet(this.props.navigation.getState(), 'routes', []);
- const dateOfBirthRoute = _.find(routes, (route) => route.name === 'Settings_PersonalDetails_DateOfBirth');
-
- if (dateOfBirthRoute) {
- Navigation.setParams({year: selectedYear.toString()}, lodashGet(dateOfBirthRoute, 'key', ''));
- Navigation.goBack();
- } else {
- Navigation.goBack(`${ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH}?year=${selectedYear}`);
- }
- }
-
- /**
- * Function filtering the list of the items when using search input
- *
- * @param {String} text
- */
- filterYearList(text) {
- const searchText = text.replace(CONST.REGEX.NON_NUMERIC, '');
- this.setState((prevState) => {
- if (searchText === prevState.inputText) {
- return {};
- }
- return {
- inputText: searchText,
- yearOptions: _.filter(this.yearList, (year) => year.text.includes(searchText)),
- };
- });
- }
-
- render() {
- const headerMessage = this.state.inputText.trim() && !this.state.yearOptions.length ? this.props.translate('common.noResultsFound') : '';
- return (
-
- Navigation.goBack(`${this.props.route.params.backTo}?year=${this.currentYear}` || ROUTES.HOME)}
- />
- this.updateSelectedYear(option.value)}
- initiallyFocusedOptionKey={this.currentYear.toString()}
- />
-
- );
- }
-}
-
-YearPickerPage.propTypes = propTypes;
-YearPickerPage.defaultProps = defaultProps;
-
-export default withLocalize(YearPickerPage);
diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
index a0a6d2394314..422e31ee9fdf 100644
--- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
+++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
@@ -1,21 +1,20 @@
-import React, {useCallback} from 'react';
+import moment from 'moment';
import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
-import moment from 'moment';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
+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';
import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import Form from '../../../../components/Form';
-import ONYXKEYS from '../../../../ONYXKEYS';
+import Navigation from '../../../../libs/Navigation/Navigation';
import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import styles from '../../../../styles/styles';
import * as PersonalDetails from '../../../../libs/actions/PersonalDetails';
import compose from '../../../../libs/compose';
-import NewDatePicker from '../../../../components/NewDatePicker';
-import CONST from '../../../../CONST';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
+import styles from '../../../../styles/styles';
const propTypes = {
/* Onyx Props */
@@ -34,16 +33,7 @@ const defaultProps = {
},
};
-function DateOfBirthPage({translate, route, privatePersonalDetails}) {
- /**
- * The year should be set on the route when navigating back from the year picker
- * This lets us pass the selected year without having to overwrite the value in Onyx
- */
- const dobYear = String(moment(privatePersonalDetails.dob).year());
- const selectedYear = lodashGet(route.params, 'year', dobYear);
- const minDate = moment().subtract(CONST.DATE_BIRTH.MAX_AGE, 'Y').toDate();
- const maxDate = moment().subtract(CONST.DATE_BIRTH.MIN_AGE, 'Y').toDate();
-
+function DateOfBirthPage({translate, privatePersonalDetails}) {
/**
* @param {Object} values
* @param {String} values.dob - date of birth
@@ -83,9 +73,8 @@ function DateOfBirthPage({translate, route, privatePersonalDetails}) {
inputID="dob"
label={translate('common.date')}
defaultValue={privatePersonalDetails.dob || ''}
- minDate={minDate}
- maxDate={maxDate}
- selectedYear={selectedYear}
+ minDate={moment().subtract(CONST.DATE_BIRTH.MAX_AGE, 'years').toDate()}
+ maxDate={moment().subtract(CONST.DATE_BIRTH.MIN_AGE, 'years').toDate()}
/>
diff --git a/src/styles/styles.js b/src/styles/styles.js
index fc226669696e..7e639f1c246d 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -827,6 +827,7 @@ const styles = {
alignItems: 'center',
paddingHorizontal: 15,
paddingRight: 5,
+ ...userSelect.userSelectNone,
},
calendarDayRoot: {
@@ -834,6 +835,7 @@ const styles = {
height: 45,
justifyContent: 'center',
alignItems: 'center',
+ ...userSelect.userSelectNone,
},
calendarDayContainer: {
@@ -1175,6 +1177,11 @@ const styles = {
height: '100%',
},
+ sidebarAnimatedWrapperContainer: {
+ height: '100%',
+ position: 'absolute',
+ },
+
sidebarFooter: {
alignItems: 'center',
display: 'flex',
diff --git a/tests/unit/CalendarPickerTest.js b/tests/unit/CalendarPickerTest.js
index 8313f8d709d5..71e31695a801 100644
--- a/tests/unit/CalendarPickerTest.js
+++ b/tests/unit/CalendarPickerTest.js
@@ -1,6 +1,6 @@
import {render, fireEvent, within} from '@testing-library/react-native';
import moment from 'moment';
-import CalendarPicker from '../../src/components/CalendarPicker';
+import CalendarPicker from '../../src/components/NewDatePicker/CalendarPicker';
import CONST from '../../src/CONST';
moment.locale(CONST.LOCALES.EN);
@@ -11,21 +11,24 @@ jest.mock('@react-navigation/native', () => ({
createNavigationContainerRef: jest.fn(),
}));
-// eslint-disable-next-line arrow-body-style
-function MockedCalendarPicker(props) {
- return (
- ''}
- preferredLocale={CONST.LOCALES.EN}
- />
- );
-}
+jest.mock('../../src/components/withLocalize', () => (Component) => (props) => (
+ ''}
+ preferredLocale="en"
+ />
+));
+
+jest.mock('../../src/hooks/useLocalize', () =>
+ jest.fn(() => ({
+ translate: jest.fn(),
+ })),
+);
describe('CalendarPicker', () => {
test('renders calendar component', () => {
- render();
+ render();
});
test('displays the current month and year', () => {
@@ -33,7 +36,7 @@ describe('CalendarPicker', () => {
const maxDate = moment(currentDate).add(1, 'Y').toDate();
const minDate = moment(currentDate).subtract(1, 'Y').toDate();
const {getByText} = render(
- ,
@@ -47,7 +50,7 @@ describe('CalendarPicker', () => {
const minDate = new Date('2022-01-01');
const maxDate = new Date('2030-01-01');
const {getByTestId, getByText} = render(
- ,
@@ -60,7 +63,7 @@ describe('CalendarPicker', () => {
});
test('clicking previous month arrow updates the displayed month', () => {
- const {getByTestId, getByText} = render();
+ const {getByTestId, getByText} = render();
fireEvent.press(getByTestId('prev-month-arrow'));
@@ -74,7 +77,7 @@ describe('CalendarPicker', () => {
const maxDate = new Date('2030-01-01');
const value = '2023-01-01';
const {getByText} = render(
- {
const minDate = new Date('2022-01-01');
const maxDate = new Date('2030-01-01');
const {getByText, getByTestId} = render(
- {
const minDate = new Date('2003-02-01');
const value = new Date('2003-02-17');
const {getByTestId} = render(
- ,
@@ -125,7 +128,7 @@ describe('CalendarPicker', () => {
const maxDate = new Date('2003-02-24');
const value = '2003-02-17';
const {getByTestId} = render(
- ,
@@ -138,7 +141,7 @@ describe('CalendarPicker', () => {
const onSelectedMock = jest.fn();
const maxDate = new Date('2011-03-01');
const {getByText} = render(
- ,
@@ -151,7 +154,7 @@ describe('CalendarPicker', () => {
test('should open the calendar on a year from max date if it is earlier than current year', () => {
const maxDate = new Date('2011-03-01');
- const {getByTestId} = render();
+ const {getByTestId} = render();
expect(within(getByTestId('currentYearText')).getByText('2011')).toBeTruthy();
});
@@ -160,7 +163,7 @@ describe('CalendarPicker', () => {
const minDate = new Date('2035-02-16');
const maxDate = new Date('2040-02-16');
const {getByTestId} = render(
- ,
@@ -173,7 +176,7 @@ describe('CalendarPicker', () => {
const value = '2003-02-17';
const minDate = new Date('2003-02-16');
const {getByLabelText} = render(
- ,
@@ -186,7 +189,7 @@ describe('CalendarPicker', () => {
const value = '2003-02-17';
const maxDate = new Date('2003-02-24');
const {getByLabelText} = render(
- ,
@@ -199,7 +202,7 @@ describe('CalendarPicker', () => {
const value = '2003-02-17';
const minDate = new Date('2003-02-16');
const {getByLabelText} = render(
- ,
@@ -212,7 +215,7 @@ describe('CalendarPicker', () => {
const value = '2003-02-17';
const maxDate = new Date('2003-02-24');
const {getByLabelText} = render(
- ,
diff --git a/tests/unit/generateMonthMatrixTest.js b/tests/unit/generateMonthMatrixTest.js
index b36ccc29f547..9f565a6e3a78 100644
--- a/tests/unit/generateMonthMatrixTest.js
+++ b/tests/unit/generateMonthMatrixTest.js
@@ -1,4 +1,4 @@
-import generateMonthMatrix from '../../src/components/CalendarPicker/generateMonthMatrix';
+import generateMonthMatrix from '../../src/components/NewDatePicker/CalendarPicker/generateMonthMatrix';
describe('generateMonthMatrix', () => {
it('returns the correct matrix for January 2022', () => {