Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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