diff --git a/Mobile-Expensify b/Mobile-Expensify
index 39615dc20653..dce6ea980d1d 160000
--- a/Mobile-Expensify
+++ b/Mobile-Expensify
@@ -1 +1 @@
-Subproject commit 39615dc206531abec3507fc026bdb5d69d3358fb
+Subproject commit dce6ea980d1da919ea7d0c38556b1989fe82ddcc
diff --git a/android/app/build.gradle b/android/app/build.gradle
index b37622a29358..8cb94527e91c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -111,8 +111,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009040204
- versionName "9.4.2-4"
+ versionCode 1009040205
+ versionName "9.4.2-5"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 41f05dafa106..305cea95b447 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -44,7 +44,7 @@
CFBundleVersion
- 9.4.2.4
+ 9.4.2.5
FullStory
OrgId
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index f054a275fb32..41315030de31 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.4.2
CFBundleVersion
- 9.4.2.4
+ 9.4.2.5
NSExtension
NSExtensionPointIdentifier
diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist
index d3d4a4cfcd86..32e8d646c18d 100644
--- a/ios/ShareViewController/Info.plist
+++ b/ios/ShareViewController/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.4.2
CFBundleVersion
- 9.4.2.4
+ 9.4.2.5
NSExtension
NSExtensionAttributes
diff --git a/package-lock.json b/package-lock.json
index 311e9c0d57ee..33ab9047f5fc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "9.4.2-4",
+ "version": "9.4.2-5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.4.2-4",
+ "version": "9.4.2-5",
"hasInstallScript": true,
"license": "MIT",
"workspaces": [
diff --git a/package.json b/package.json
index ec8b9fe0c1dd..a553e030f3e8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.4.2-4",
+ "version": "9.4.2-5",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index ccc870861aaf..c529fe8a3825 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -821,10 +821,6 @@ const DYNAMIC_ROUTES = {
entryScreens: [SCREENS.REPORT, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT],
getRoute: (reportID: string, reportActionID: string) => `flag/${reportID}/${reportActionID}`,
},
- WORKSPACE_REPORT_FIELDS_INITIAL_LIST_VALUE: {
- path: 'initial-list-value',
- entryScreens: [SCREENS.WORKSPACE.REPORT_FIELDS_CREATE],
- },
} as const satisfies DynamicRoutes;
const ROUTES = {
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index a8f15dfe8b1e..87846db73b96 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -795,7 +795,6 @@ const SCREENS = {
REPORT_FIELDS_VALUE_SETTINGS: 'Workspace_ReportFields_ValueSettings',
REPORT_FIELDS_EDIT_VALUE: 'Workspace_ReportFields_EditValue',
REPORT_FIELDS_EDIT_INITIAL_VALUE: 'Workspace_ReportFields_EditInitialValue',
- DYNAMIC_REPORT_FIELDS_INITIAL_LIST_VALUE: 'Dynamic_Report_Fields_Initial_List_Value',
TAX_EDIT: 'Workspace_Tax_Edit',
TAX_NAME: 'Workspace_Tax_Name',
TAX_VALUE: 'Workspace_Tax_Value',
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 9a04e5227ff5..6c85e957e7c3 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -995,8 +995,6 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Subscription/PaymentCard').default),
[SCREENS.WORKSPACE.REPORT_FIELDS_CREATE]: () => require('../../../../pages/workspace/reports/CreateReportFieldsPage').default,
- [SCREENS.WORKSPACE.DYNAMIC_REPORT_FIELDS_INITIAL_LIST_VALUE]: () =>
- require('../../../../pages/workspace/reports/InitialListValueSelector/DynamicReportFieldsInitialListValuePage').default,
[SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS]: () => require('../../../../pages/workspace/reports/ReportFieldsSettingsPage').default,
[SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: () => require('../../../../pages/workspace/reports/ReportFieldsListValuesPage').default,
[SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: () => require('../../../../pages/workspace/reports/ReportFieldsAddListValuePage').default,
diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
index 11996b30806c..61591fffedac 100755
--- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
+++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts
@@ -295,7 +295,6 @@ const WORKSPACE_TO_RHP: Partial['config'] = {
[SCREENS.WORKSPACE.REPORT_FIELDS_CREATE]: {
path: ROUTES.WORKSPACE_CREATE_REPORT_FIELD.route,
},
- [SCREENS.WORKSPACE.DYNAMIC_REPORT_FIELDS_INITIAL_LIST_VALUE]: DYNAMIC_ROUTES.WORKSPACE_REPORT_FIELDS_INITIAL_LIST_VALUE.path,
[SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: {
path: ROUTES.WORKSPACE_REPORT_FIELDS_LIST_VALUES.route,
},
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 77ca6538a3da..7286e5b88eb2 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -644,9 +644,6 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.REPORT_FIELDS_CREATE]: {
policyID: string;
};
- [SCREENS.WORKSPACE.DYNAMIC_REPORT_FIELDS_INITIAL_LIST_VALUE]: {
- policyID: string;
- };
[SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: {
policyID: string;
reportFieldID?: string;
diff --git a/src/pages/workspace/reports/InitialListValueSelector/DynamicReportFieldsInitialListValuePage.tsx b/src/pages/workspace/reports/InitialListValueSelector/DynamicReportFieldsInitialListValuePage.tsx
deleted file mode 100644
index be0ed13553d4..000000000000
--- a/src/pages/workspace/reports/InitialListValueSelector/DynamicReportFieldsInitialListValuePage.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import React, {useEffect} from 'react';
-import {View} from 'react-native';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import ScreenWrapper from '@components/ScreenWrapper';
-import Text from '@components/Text';
-import useDynamicBackPath from '@hooks/useDynamicBackPath';
-import useLocalize from '@hooks/useLocalize';
-import useOnyx from '@hooks/useOnyx';
-import useThemeStyles from '@hooks/useThemeStyles';
-import {setDraftValues} from '@libs/actions/FormActions';
-import Navigation from '@libs/Navigation/Navigation';
-import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
-import {hasAccountingConnections} from '@libs/PolicyUtils';
-import type {SettingsNavigatorParamList} from '@navigation/types';
-import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
-import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
-import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES';
-import type SCREENS from '@src/SCREENS';
-import INPUT_IDS from '@src/types/form/WorkspaceReportFieldForm';
-import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
-import ReportFieldsInitialListValuePicker from './ReportFieldsInitialListValuePicker';
-
-type DynamicReportFieldsInitialListValuePageProps = WithPolicyAndFullscreenLoadingProps &
- PlatformStackScreenProps;
-
-function DynamicReportFieldsInitialListValuePage({
- policy,
- route: {
- params: {policyID},
- },
-}: DynamicReportFieldsInitialListValuePageProps) {
- const styles = useThemeStyles();
- const {translate} = useLocalize();
- const [formDraft, formDraftMetadata] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT);
- const backPath = useDynamicBackPath(DYNAMIC_ROUTES.WORKSPACE_REPORT_FIELDS_INITIAL_LIST_VALUE.path);
-
- const currentValue = formDraft?.[INPUT_IDS.INITIAL_VALUE] ?? '';
- const listValues = formDraft?.[INPUT_IDS.LIST_VALUES] ?? [];
-
- // When this page is reached via deeplink or restored after a page refresh, the parent CreateReportFieldsPage resets
- // the create-field draft on mount, leaving no list values to choose from. In that case, return to the Add field
- // page instead of stranding the user on an empty picker. On refresh the dynamic route restores without its parent
- // in the stack, so the dynamic back path resolves to the report fields settings page rather than the Add field page
- // — target the Add field route explicitly to land there.
- useEffect(() => {
- if (isLoadingOnyxValue(formDraftMetadata) || listValues.length > 0) {
- return;
- }
- Navigation.goBack(ROUTES.WORKSPACE_CREATE_REPORT_FIELD.getRoute(policyID));
- }, [formDraftMetadata, listValues.length, policyID]);
-
- const onValueSelected = (value: string) => {
- setDraftValues(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM, {
- [INPUT_IDS.INITIAL_VALUE]: currentValue === value ? '' : value,
- });
- Navigation.goBack(backPath);
- };
-
- return (
-
-
- Navigation.goBack(backPath)}
- />
-
- {translate('workspace.reportFields.listValuesInputSubtitle')}
-
-
-
-
- );
-}
-
-export default withPolicyAndFullscreenLoading(DynamicReportFieldsInitialListValuePage);
diff --git a/src/pages/workspace/reports/InitialListValueSelector/InitialListValueSelectorModal.tsx b/src/pages/workspace/reports/InitialListValueSelector/InitialListValueSelectorModal.tsx
new file mode 100644
index 000000000000..a6d39b3ee6cf
--- /dev/null
+++ b/src/pages/workspace/reports/InitialListValueSelector/InitialListValueSelectorModal.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import {View} from 'react-native';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Modal from '@components/Modal';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import useOnyx from '@hooks/useOnyx';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ReportFieldsInitialListValuePicker from './ReportFieldsInitialListValuePicker';
+
+type InitialListValueSelectorModalProps = {
+ /** Whether the modal is visible */
+ isVisible: boolean;
+
+ /** Selected value */
+ currentValue: string;
+
+ /** Label to display on field */
+ label: string;
+
+ /** Subtitle to display on field */
+ subtitle: string;
+
+ /** Function to call when the user selects a value */
+ onValueSelected: (value: string) => void;
+
+ /** Function to call when the user closes the value selector modal */
+ onClose: () => void;
+};
+
+function InitialListValueSelectorModal({isVisible, currentValue, label, subtitle, onValueSelected, onClose}: InitialListValueSelectorModalProps) {
+ const styles = useThemeStyles();
+
+ const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT);
+
+ return (
+
+
+
+
+ {subtitle}
+
+
+
+
+ );
+}
+
+export default InitialListValueSelectorModal;
diff --git a/src/pages/workspace/reports/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx b/src/pages/workspace/reports/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx
index 9592234e92ff..e57a8b862b06 100644
--- a/src/pages/workspace/reports/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx
+++ b/src/pages/workspace/reports/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx
@@ -39,7 +39,6 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value,
ListItem={SingleSelectListItem}
onSelectRow={(item) => onValueChange(item.value)}
initiallyFocusedItemKey={listValueOptions.find((listValue) => listValue.isSelected)?.keyForList}
- shouldSingleExecuteRowSelect
addBottomSafeAreaPadding
/>
);
diff --git a/src/pages/workspace/reports/InitialListValueSelector/index.tsx b/src/pages/workspace/reports/InitialListValueSelector/index.tsx
index fac4128b34a5..0ea7cb414b64 100644
--- a/src/pages/workspace/reports/InitialListValueSelector/index.tsx
+++ b/src/pages/workspace/reports/InitialListValueSelector/index.tsx
@@ -1,19 +1,21 @@
import type {ForwardedRef} from 'react';
-import React, {useEffect} from 'react';
+import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import type {MenuItemBaseProps} from '@components/MenuItem';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import useOnyx from '@hooks/useOnyx';
-import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
-import Navigation from '@libs/Navigation/Navigation';
+import blurActiveElement from '@libs/Accessibility/blurActiveElement';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import {DYNAMIC_ROUTES} from '@src/ROUTES';
+import InitialListValueSelectorModal from './InitialListValueSelectorModal';
type InitialListValueSelectorProps = Pick & {
/** Currently selected value */
value?: string;
+ /** Subtitle to display on field */
+ subtitle?: string;
+
/** Function to call when the user selects a value */
onInputChange?: (value: string) => void;
@@ -21,9 +23,25 @@ type InitialListValueSelectorProps = Pick;
};
-function InitialListValueSelector({value = '', label = '', rightLabel, errorText = '', onInputChange, ref}: InitialListValueSelectorProps) {
+function InitialListValueSelector({value = '', label = '', rightLabel, subtitle = '', errorText = '', onInputChange, ref}: InitialListValueSelectorProps) {
const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT);
+ const [isPickerVisible, setIsPickerVisible] = useState(false);
+
+ const showPickerModal = () => {
+ setIsPickerVisible(true);
+ };
+
+ const hidePickerModal = () => {
+ setIsPickerVisible(false);
+ blurActiveElement();
+ };
+
+ const updateValueInput = (initialValue: string) => {
+ onInputChange?.(value === initialValue ? '' : initialValue);
+ hidePickerModal();
+ };
+
useEffect(() => {
const currentValueIndex = Object.values(formDraft?.listValues ?? {}).findIndex((listValue) => listValue === value);
const isCurrentValueDisabled = formDraft?.disabledListValues?.[currentValueIndex] ?? true;
@@ -43,7 +61,15 @@ function InitialListValueSelector({value = '', label = '', rightLabel, errorText
rightLabel={rightLabel}
brickRoadIndicator={errorText ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
errorText={errorText}
- onPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_REPORT_FIELDS_INITIAL_LIST_VALUE.path))}
+ onPress={showPickerModal}
+ />
+
);