Skip to content
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,9 @@ const ONYXKEYS = {
/** Stores the role selected for members being imported from a spreadsheet */
IMPORTED_SPREADSHEET_MEMBER_ROLE: 'importedSpreadsheetMemberRole',

/** Stores the year selected in the year picker so it can be read back by the CalendarPicker that opened it */
CALENDAR_PICKER_SELECTED_YEAR: 'calendarPickerSelectedYear',

/** Stores the route to open after changing app permission from settings */
LAST_ROUTE: 'lastRoute',

Expand Down Expand Up @@ -1575,6 +1578,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.IMPORTED_SPREADSHEET]: OnyxTypes.ImportedSpreadsheet;
[ONYXKEYS.IMPORTED_SPREADSHEET_MEMBER_DATA]: OnyxTypes.ImportedSpreadsheetMemberData[];
[ONYXKEYS.IMPORTED_SPREADSHEET_MEMBER_ROLE]: ValueOf<typeof CONST.POLICY.ROLE>;
[ONYXKEYS.CALENDAR_PICKER_SELECTED_YEAR]: {contextID: string; year: number};
[ONYXKEYS.LAST_ROUTE]: string;
[ONYXKEYS.IS_USING_IMPORTED_STATE]: boolean;
[ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record<string, string>;
Expand Down
12 changes: 12 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ const DYNAMIC_ROUTES = {
path: 'imported-members-role',
entryScreens: [SCREENS.WORKSPACE.MEMBERS_IMPORTED_CONFIRMATION],
},
YEAR_SELECTOR: {
path: 'year-selector',
queryParams: ['contextID', 'currentYear', 'minYear', 'maxYear'],
// CalendarPicker is a generic component reached from many screens (date input fields,
// DateSelectPopup, RangeDatePicker, DatePresetFilterBase, ScheduleCallPage, ...), and the
// previous in-place YearPickerModal had no screen restriction. Use '*' so the year selector
// remains reachable from every CalendarPicker host and doesn't silently break when new
// date-input screens are added (matches KEYBOARD_SHORTCUTS / EXIT_SURVEY_* generic flows).
entryScreens: ['*'],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add a getRoute handler here to add queryParams.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in cd94220 — added a getRoute on YEAR_SELECTOR that takes {contextID, currentYear, minYear, maxYear} and goes through getUrlWithParams('year-selector', …) so encoding stays in one place and matches the declared queryParams.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in cd94220YEAR_SELECTOR now has a typed getRoute({contextID, currentYear, minYear, maxYear}) handler that builds the query params via getUrlWithParams.

getRoute: ({contextID, currentYear, minYear, maxYear}: {contextID: string; currentYear: number; minYear: number; maxYear: number}) =>
getUrlWithParams('year-selector', {contextID, currentYear, minYear, maxYear}),
},
REPORT_SETTINGS_NAME: {
path: 'settings/name',
entryScreens: [SCREENS.REPORT_DETAILS.ROOT],
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ const SCREENS = {
HELP: 'Settings_Help',
DYNAMIC_VERIFY_ACCOUNT: 'Dynamic_Verify_Account',
DYNAMIC_ADD_BANK_ACCOUNT_VERIFY_ACCOUNT: 'Dynamic_Add_Bank_Account_Verify_Account',
DYNAMIC_YEAR_SELECTOR: 'Dynamic_Year_Selector',
DYNAMIC_EXIT_SURVEY_CONFIRM: 'Dynamic_ExitSurvey_Confirm',
DYNAMIC_EXIT_SURVEY_REASON: 'Dynamic_ExitSurvey_Reason',
DYNAMIC_KEYBOARD_SHORTCUTS: 'Dynamic_Keyboard_Shortcuts',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, {useMemo, useState} from 'react';
import {Keyboard} from 'react-native';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import SingleSelectListItem from '@components/SelectionList/ListItem/SingleSelectListItem';
import useDynamicBackPath from '@hooks/useDynamicBackPath';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import {setCalendarPickerSelectedYear} from '@libs/actions/CalendarPicker';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@navigation/types';
import CONST from '@src/CONST';
import {DYNAMIC_ROUTES} from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type CalendarPickerListItem from './types';

type DynamicYearSelectorPageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.DYNAMIC_YEAR_SELECTOR>;

function DynamicYearSelectorPage({route}: DynamicYearSelectorPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const backPath = useDynamicBackPath(DYNAMIC_ROUTES.YEAR_SELECTOR.path);

const {contextID} = route.params;
const currentYear = Number(route.params.currentYear) || new Date().getFullYear();
const minYear = Number(route.params.minYear) || CONST.CALENDAR_PICKER.MIN_YEAR;
const maxYear = Number(route.params.maxYear) || CONST.CALENDAR_PICKER.MAX_YEAR;

const [searchText, setSearchText] = useState('');

const years: CalendarPickerListItem[] = useMemo(
() =>
Array.from({length: maxYear - minYear + 1}, (value, index) => index + minYear).map((year) => ({
text: year.toString(),
value: year,
keyForList: year.toString(),
isSelected: year === currentYear,
})),
[minYear, maxYear, currentYear],
);

const {data, headerMessage} = useMemo(() => {
const yearsList = searchText === '' ? years : years.filter((year) => year.text?.includes(searchText));
return {
headerMessage: !yearsList.length ? translate('common.noResultsFound') : '',
data: yearsList.sort((a, b) => b.value - a.value),
};
}, [years, searchText, translate]);

const textInputOptions = useMemo(
() => ({
label: translate('yearPickerPage.selectYear'),
value: searchText,
onChangeText: (text: string) => setSearchText(text.replaceAll(CONST.REGEX.NON_NUMERIC, '').trim()),
headerMessage,
maxLength: 4,
inputMode: CONST.INPUT_MODE.NUMERIC,
}),
[headerMessage, searchText, translate],
);

return (
<ScreenWrapper
style={[styles.pb0]}
includePaddingTop={false}
enableEdgeToEdgeBottomSafeAreaPadding
testID="DynamicYearSelectorPage"
>
<HeaderWithBackButton
title={translate('yearPickerPage.year')}
onBackButtonPress={() => Navigation.goBack(backPath)}
/>
<SelectionList
data={data}
ListItem={SingleSelectListItem}
onSelectRow={(option) => {
Keyboard.dismiss();
setCalendarPickerSelectedYear(contextID, option.value);
Navigation.goBack(backPath);
}}
textInputOptions={textInputOptions}
initiallyFocusedItemKey={currentYear.toString()}
disableMaintainingScrollPosition
addBottomSafeAreaPadding
shouldStopPropagation
showScrollIndicator
/>
</ScreenWrapper>
);
}

export default DynamicYearSelectorPage;
105 changes: 0 additions & 105 deletions src/components/DatePicker/CalendarPicker/YearPickerModal.tsx

This file was deleted.

Loading
Loading