From 059d144f2daad4327e988947b867f26c2d646a08 Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Fri, 20 Mar 2026 00:56:08 +0530 Subject: [PATCH 1/5] feat: add keyboard shortcuts for dynamic route --- src/ROUTES.ts | 24 +++++++++++++------ src/SCREENS.ts | 2 +- .../ShortcutsOverviewHandler.tsx | 9 ++++--- .../ModalStackNavigators/index.tsx | 2 +- src/libs/Navigation/linkingConfig/config.ts | 4 +--- src/libs/Navigation/types.ts | 5 +--- src/pages/settings/AboutPage/AboutPage.tsx | 5 ++-- .../DynamicKeyboardShortcutsPage.tsx} | 23 +++++++----------- .../findMatchingDynamicSuffixTests.ts | 4 ++++ 9 files changed, 42 insertions(+), 36 deletions(-) rename src/pages/{KeyboardShortcutsPage.tsx => settings/DynamicKeyboardShortcutsPage.tsx} (78%) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8ebcd8d6a5ba..7eb0ba7100e5 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -116,6 +116,23 @@ const DYNAMIC_ROUTES = { getRoute: (country = '') => `country?country=${country}`, queryParams: ['country'], }, + KEYBOARD_SHORTCUTS: { + path: 'keyboard-shortcuts', + entryScreens: [ + SCREENS.HOME, + SCREENS.REPORT, + SCREENS.SEARCH.ROOT, + SCREENS.SETTINGS.ROOT, + SCREENS.SETTINGS.ABOUT, + SCREENS.SETTINGS.WALLET.ROOT, + SCREENS.SETTINGS.PREFERENCES.ROOT, + SCREENS.SETTINGS.PROFILE.ROOT, + SCREENS.SETTINGS.SECURITY, + SCREENS.RIGHT_MODAL.SEARCH_REPORT, + SCREENS.RIGHT_MODAL.EXPENSE_REPORT, + SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, + ], + }, } as const satisfies DynamicRoutes; const ROUTES = { @@ -631,13 +648,6 @@ const ROUTES = { SETTINGS_SAVE_THE_WORLD: 'settings/teachersunite', - KEYBOARD_SHORTCUTS: { - route: 'keyboard-shortcuts', - - // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - getRoute: (backTo?: string) => getUrlWithBackToParam('keyboard-shortcuts', backTo), - }, - NEW: 'new', NEW_CHAT: 'new/chat', NEW_CHAT_CONFIRM: 'new/chat/confirm', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 961e91096423..2c20eb3bd999 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -120,6 +120,7 @@ const SCREENS = { TROUBLESHOOT: 'Settings_Troubleshoot', DYNAMIC_VERIFY_ACCOUNT: 'Dynamic_Verify_Account', DYNAMIC_ADD_BANK_ACCOUNT_VERIFY_ACCOUNT: 'Dynamic_Add_Bank_Account_Verify_Account', + DYNAMIC_KEYBOARD_SHORTCUTS: 'Dynamic_Keyboard_Shortcuts', PROFILE: { ROOT: 'Settings_Profile', @@ -900,7 +901,6 @@ const SCREENS = { REFERRAL_DETAILS: 'Referral_Details', REPORT_VERIFY_ACCOUNT: 'Report_Verify_Account', EXPENSE_REPORT_VERIFY_ACCOUNT: 'Expense_Report_Verify_Account', - KEYBOARD_SHORTCUTS: 'KeyboardShortcuts', SHARE: { ROOT: 'Share_Root', SHARE_DETAILS: 'Share_Details', diff --git a/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx b/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx index ca67c783c73f..d8d36a80e513 100644 --- a/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx +++ b/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx @@ -1,10 +1,12 @@ import {useEffect} from 'react'; import useShouldShowRequire2FAPage from '@hooks/useShouldShowRequire2FAPage'; import KeyboardShortcut from '@libs/KeyboardShortcut'; +import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; +import findMatchingDynamicSuffix from '@libs/Navigation/helpers/dynamicRoutesUtils/findMatchingDynamicSuffix'; import Navigation from '@libs/Navigation/Navigation'; import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; function ShortcutsOverviewHandler() { const shouldShowRequire2FAPage = useShouldShowRequire2FAPage(); @@ -19,10 +21,11 @@ function ShortcutsOverviewHandler() { return; } - if (Navigation.isActiveRoute(ROUTES.KEYBOARD_SHORTCUTS.getRoute(Navigation.getActiveRoute()))) { + const activeRoute = Navigation.getActiveRoute(); + if (findMatchingDynamicSuffix(activeRoute) === DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path) { return; } - return Navigation.navigate(ROUTES.KEYBOARD_SHORTCUTS.getRoute(Navigation.getActiveRoute())); + return Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path)); }); }, shortcutConfig.descriptionKey, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index a96f23e120f9..72cdf911ef6e 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -627,7 +627,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/ReimbursementAccount/EnterSignerInfo').default, [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: () => require('../../../../pages/settings/Wallet/ReportCardLostPage').default, [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE]: () => require('../../../../pages/settings/Wallet/ReportCardLostConfirmMagicCodePage').default, - [SCREENS.KEYBOARD_SHORTCUTS]: () => require('../../../../pages/KeyboardShortcutsPage').default, + [SCREENS.SETTINGS.DYNAMIC_KEYBOARD_SHORTCUTS]: () => require('../../../../pages/settings/DynamicKeyboardShortcutsPage').default, [SCREENS.SETTINGS.EXIT_SURVEY.REASON]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyReasonPage').default, [SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyConfirmPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT]: () => require('../../../../pages/workspace/accounting/qbo/import/QuickbooksImportPage').default, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 571698d0a94e..205394c4c925 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1150,9 +1150,7 @@ const config: LinkingOptions['config'] = { exact: true, }, [SCREENS.REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO]: ROUTES.BANK_ACCOUNT_ENTER_SIGNER_INFO.route, - [SCREENS.KEYBOARD_SHORTCUTS]: { - path: ROUTES.KEYBOARD_SHORTCUTS.route, - }, + [SCREENS.SETTINGS.DYNAMIC_KEYBOARD_SHORTCUTS]: DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path, [SCREENS.WORKSPACE.NAME]: ROUTES.WORKSPACE_OVERVIEW_NAME.route, [SCREENS.SETTINGS.SHARE_CODE]: { path: ROUTES.SETTINGS_SHARE_CODE, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 82f78383a616..2fdad42d454f 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1175,10 +1175,7 @@ type SettingsNavigatorParamList = { /** Reason for replacing the card */ reason: ReplacementReason; }; - [SCREENS.KEYBOARD_SHORTCUTS]: { - // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md - backTo: Routes; - }; + [SCREENS.SETTINGS.DYNAMIC_KEYBOARD_SHORTCUTS]: undefined; [SCREENS.SETTINGS.EXIT_SURVEY.REASON]: { // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md backTo: Routes; diff --git a/src/pages/settings/AboutPage/AboutPage.tsx b/src/pages/settings/AboutPage/AboutPage.tsx index 075d845f258c..60f07bfbd062 100644 --- a/src/pages/settings/AboutPage/AboutPage.tsx +++ b/src/pages/settings/AboutPage/AboutPage.tsx @@ -19,6 +19,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {isInternalTestBuild} from '@libs/Environment/Environment'; +import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; import {showContextMenu} from '@pages/inbox/report/ContextMenu/ReportActionContextMenu'; import colors from '@styles/theme/colors'; @@ -27,7 +28,7 @@ import {navigateToConciergeChat} from '@userActions/Report'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; +import ROUTES, {DYNAMIC_ROUTES} from '@src/ROUTES'; import type IconAsset from '@src/types/utils/IconAsset'; import type WithSentryLabel from '@src/types/utils/SentryLabel'; import pkg from '../../../../package.json'; @@ -79,7 +80,7 @@ function AboutPage() { translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts', icon: icons.Keyboard, sentryLabel: CONST.SENTRY_LABEL.SETTINGS_ABOUT.VIEW_KEYBOARD_SHORTCUTS, - action: waitForNavigate(() => Navigation.navigate(ROUTES.KEYBOARD_SHORTCUTS.getRoute(Navigation.getActiveRoute()))), + action: waitForNavigate(() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path))), }, { translationKey: 'initialSettingsPage.aboutPage.viewTheCode', diff --git a/src/pages/KeyboardShortcutsPage.tsx b/src/pages/settings/DynamicKeyboardShortcutsPage.tsx similarity index 78% rename from src/pages/KeyboardShortcutsPage.tsx rename to src/pages/settings/DynamicKeyboardShortcutsPage.tsx index 2048e1fc8764..267ba29154a1 100644 --- a/src/pages/KeyboardShortcutsPage.tsx +++ b/src/pages/settings/DynamicKeyboardShortcutsPage.tsx @@ -1,4 +1,3 @@ -import type {RouteProp} from '@react-navigation/native'; import React from 'react'; import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -6,27 +5,24 @@ import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; +import useDynamicBackPath from '@hooks/useDynamicBackPath'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import KeyboardShortcut from '@libs/KeyboardShortcut'; import Navigation from '@libs/Navigation/Navigation'; -import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; -import type SCREENS from '@src/SCREENS'; +import {DYNAMIC_ROUTES} from '@src/ROUTES'; type Shortcut = { displayName: string; descriptionKey: 'search' | 'newChat' | 'openShortcutDialog' | 'escape' | 'copy'; }; -type KeyboardShortcutsPageProps = { - route: RouteProp; -}; - -function KeyboardShortcutsPage({route}: KeyboardShortcutsPageProps) { +function DynamicKeyboardShortcutsPage() { const styles = useThemeStyles(); const {translate} = useLocalize(); - const backTo = route.params.backTo; + const backPath = useDynamicBackPath(DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path); + const shortcuts = Object.values(CONST.KEYBOARD_SHORTCUTS) .map((shortcut) => { const platformAdjustedModifiers = KeyboardShortcut.getPlatformEquivalentForKeys(shortcut.modifiers); @@ -36,10 +32,7 @@ function KeyboardShortcutsPage({route}: KeyboardShortcutsPageProps) { }; }) .filter((shortcut): shortcut is Shortcut => !!shortcut.descriptionKey); - /** - * Render the information of a single shortcut - * @param shortcut - The shortcut to render - */ + const renderShortcut = (shortcut: Shortcut) => ( Navigation.goBack(backTo)} + onBackButtonPress={() => Navigation.goBack(backPath)} /> @@ -69,4 +62,4 @@ function KeyboardShortcutsPage({route}: KeyboardShortcutsPageProps) { ); } -export default KeyboardShortcutsPage; +export default DynamicKeyboardShortcutsPage; diff --git a/tests/navigation/findMatchingDynamicSuffixTests.ts b/tests/navigation/findMatchingDynamicSuffixTests.ts index 6baaaf187d4c..6f1a76f942a9 100644 --- a/tests/navigation/findMatchingDynamicSuffixTests.ts +++ b/tests/navigation/findMatchingDynamicSuffixTests.ts @@ -36,4 +36,8 @@ describe('findMatchingDynamicSuffix', () => { it('should match a suffix when path has suffix-specific query params', () => { expect(findMatchingDynamicSuffix('settings/profile/address/country?country=US')).toBe('country'); }); + + it('should match keyboard-shortcuts dynamic suffix', () => { + expect(findMatchingDynamicSuffix('settings/about/keyboard-shortcuts')).toBe('keyboard-shortcuts'); + }); }); From 66048fd090641573cd57cfbdf834621d1a646654 Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Fri, 20 Mar 2026 01:15:16 +0530 Subject: [PATCH 2/5] fix: add workspace routes --- src/ROUTES.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7eb0ba7100e5..41c79befe7e8 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -128,6 +128,8 @@ const DYNAMIC_ROUTES = { SCREENS.SETTINGS.PREFERENCES.ROOT, SCREENS.SETTINGS.PROFILE.ROOT, SCREENS.SETTINGS.SECURITY, + SCREENS.WORKSPACES_LIST, + SCREENS.WORKSPACE.INITIAL, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, From abb4bdb88591e72c2eda258b7c8a2b396e4f5d6e Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Fri, 20 Mar 2026 01:18:06 +0530 Subject: [PATCH 3/5] fix: added pending screens --- src/ROUTES.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 41c79befe7e8..4f18205d46bf 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -122,14 +122,23 @@ const DYNAMIC_ROUTES = { SCREENS.HOME, SCREENS.REPORT, SCREENS.SEARCH.ROOT, + SCREENS.SEARCH_ROUTER.ROOT, SCREENS.SETTINGS.ROOT, SCREENS.SETTINGS.ABOUT, SCREENS.SETTINGS.WALLET.ROOT, SCREENS.SETTINGS.PREFERENCES.ROOT, SCREENS.SETTINGS.PROFILE.ROOT, SCREENS.SETTINGS.SECURITY, + SCREENS.SETTINGS.RULES.ROOT, + SCREENS.SETTINGS.SUBSCRIPTION.ROOT, + SCREENS.SETTINGS.TROUBLESHOOT, + SCREENS.SETTINGS.SAVE_THE_WORLD, SCREENS.WORKSPACES_LIST, SCREENS.WORKSPACE.INITIAL, + SCREENS.WORKSPACE.PROFILE, + SCREENS.DOMAIN.INITIAL, + SCREENS.REPORT_SETTINGS.ROOT, + SCREENS.RIGHT_MODAL.SEARCH_ROUTER, SCREENS.RIGHT_MODAL.SEARCH_REPORT, SCREENS.RIGHT_MODAL.EXPENSE_REPORT, SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, From ed9e0a471eca53da4939ea03f0ee75997d3cdaa7 Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Fri, 20 Mar 2026 01:19:24 +0530 Subject: [PATCH 4/5] fix: update path --- .../KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx b/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx index d8d36a80e513..bcabe83d8710 100644 --- a/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx +++ b/src/libs/Navigation/AppNavigator/KeyboardShortcutsHandler/ShortcutsOverviewHandler.tsx @@ -8,6 +8,8 @@ import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; import {DYNAMIC_ROUTES} from '@src/ROUTES'; +const KEYBOARD_SHORTCUTS_PATH = DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path; + function ShortcutsOverviewHandler() { const shouldShowRequire2FAPage = useShouldShowRequire2FAPage(); @@ -22,10 +24,10 @@ function ShortcutsOverviewHandler() { } const activeRoute = Navigation.getActiveRoute(); - if (findMatchingDynamicSuffix(activeRoute) === DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path) { + if (findMatchingDynamicSuffix(activeRoute) === KEYBOARD_SHORTCUTS_PATH) { return; } - return Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.KEYBOARD_SHORTCUTS.path)); + return Navigation.navigate(createDynamicRoute(KEYBOARD_SHORTCUTS_PATH)); }); }, shortcutConfig.descriptionKey, From 08e3119a1bbd2dab723e24dc74080d7174b42388 Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Fri, 27 Mar 2026 02:49:27 +0530 Subject: [PATCH 5/5] refactor: use wildcard for entry screen --- src/ROUTES.ts | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2c6144829731..3fcc01ec3206 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -122,31 +122,7 @@ const DYNAMIC_ROUTES = { }, KEYBOARD_SHORTCUTS: { path: 'keyboard-shortcuts', - entryScreens: [ - SCREENS.HOME, - SCREENS.REPORT, - SCREENS.SEARCH.ROOT, - SCREENS.SEARCH_ROUTER.ROOT, - SCREENS.SETTINGS.ROOT, - SCREENS.SETTINGS.ABOUT, - SCREENS.SETTINGS.WALLET.ROOT, - SCREENS.SETTINGS.PREFERENCES.ROOT, - SCREENS.SETTINGS.PROFILE.ROOT, - SCREENS.SETTINGS.SECURITY, - SCREENS.SETTINGS.RULES.ROOT, - SCREENS.SETTINGS.SUBSCRIPTION.ROOT, - SCREENS.SETTINGS.TROUBLESHOOT, - SCREENS.SETTINGS.SAVE_THE_WORLD, - SCREENS.WORKSPACES_LIST, - SCREENS.WORKSPACE.INITIAL, - SCREENS.WORKSPACE.PROFILE, - SCREENS.DOMAIN.INITIAL, - SCREENS.REPORT_SETTINGS.ROOT, - SCREENS.RIGHT_MODAL.SEARCH_ROUTER, - SCREENS.RIGHT_MODAL.SEARCH_REPORT, - SCREENS.RIGHT_MODAL.EXPENSE_REPORT, - SCREENS.RIGHT_MODAL.SEARCH_MONEY_REQUEST_REPORT, - ], + entryScreens: ['*'], }, } as const satisfies DynamicRoutes;