From 6f2a83a0ee2f0301b1b34db7db43da477c2fc190 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:21:10 +0100 Subject: [PATCH 01/46] redesign the TopBar --- src/components/WorkspaceSwitcherButton.tsx | 8 +- .../createCustomBottomTabNavigator/TopBar.tsx | 76 ++++++++++++++----- .../createCustomBottomTabNavigator/index.tsx | 4 +- src/pages/home/sidebar/SidebarLinks.js | 16 ---- 4 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/components/WorkspaceSwitcherButton.tsx b/src/components/WorkspaceSwitcherButton.tsx index 963782bb50d5e..314ca685e5d63 100644 --- a/src/components/WorkspaceSwitcherButton.tsx +++ b/src/components/WorkspaceSwitcherButton.tsx @@ -1,13 +1,11 @@ import React, {useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Policy} from '@src/types/onyx'; import * as Expensicons from './Icon/Expensicons'; @@ -71,8 +69,4 @@ function WorkspaceSwitcherButton({activeWorkspaceID, policy}: WorkspaceSwitcherB WorkspaceSwitcherButton.displayName = 'WorkspaceSwitcherButton'; -export default withOnyx({ - policy: { - key: ({activeWorkspaceID}) => `${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID}`, - }, -})(WorkspaceSwitcherButton); +export default WorkspaceSwitcherButton; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index 4ed8869c1eaa8..c2eddca54b3f4 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -1,36 +1,78 @@ import React from 'react'; import {View} from 'react-native'; -import Search from '@components/Search'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import Breadcrumbs from '@components/Breadcrumbs'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import {PressableWithoutFeedback} from '@components/Pressable'; +import Tooltip from '@components/Tooltip'; import WorkspaceSwitcherButton from '@components/WorkspaceSwitcherButton'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/SignInOrAvatarWithOptionalStatus'; import * as Session from '@userActions/Session'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Policy} from '@src/types/onyx'; -function TopBar() { +type TopBarOnyxProps = { + policy: OnyxEntry; +}; + +// eslint-disable-next-line react/no-unused-prop-types +type TopBarProps = {activeWorkspaceID?: string} & TopBarOnyxProps; + +function TopBar({policy}: TopBarProps) { const styles = useThemeStyles(); + const theme = useTheme(); const {translate} = useLocalize(); - const {activeWorkspaceID} = useActiveWorkspace(); + + const title = policy?.name ?? translate('common.chats'); return ( - - - Navigation.navigate(ROUTES.SEARCH))} - containerStyle={[styles.flex1]} - /> - + + + + + + + + + Navigation.navigate(ROUTES.SEARCH))} + > + + + + ); } TopBar.displayName = 'TopBar'; -export default TopBar; +export default withOnyx({ + policy: { + key: ({activeWorkspaceID}) => `${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID}`, + }, +})(TopBar); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx index bd32c6cab73c2..f5c373fa3897b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx @@ -5,6 +5,7 @@ import {StackView} from '@react-navigation/stack'; import React from 'react'; import {View} from 'react-native'; import ScreenWrapper from '@components/ScreenWrapper'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useThemeStyles from '@hooks/useThemeStyles'; import type {NavigationStateRoute} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; @@ -45,6 +46,7 @@ function CustomBottomTabNavigator({initialRouteName, children, screenOptions, .. const styles = useThemeStyles(); const stateToRender = getStateToRender(state); + const {activeWorkspaceID} = useActiveWorkspace(); return ( - + - Date: Mon, 19 Feb 2024 16:05:01 +0100 Subject: [PATCH 02/46] add Workspace section to InitialSettingsPage --- src/languages/en.ts | 1 + .../BottomTabBar.tsx | 28 ++------ src/pages/settings/InitialSettingsPage.js | 67 ++++++++++++++++++- 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 82aedf16aac52..6bb65be98da31 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -874,6 +874,7 @@ export default { accountSettings: 'Account Settings', account: 'Account', general: 'General', + workspaces: 'Workspaces', }, closeAccountPage: { closeAccount: 'Close account', diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index a953175fdcb79..18452aa259c62 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -11,12 +11,12 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import {checkIfWorkspaceSettingsTabHasRBR, getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; +import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/SignInOrAvatarWithOptionalStatus'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; @@ -87,29 +87,9 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - - - interceptAnonymousUser(() => - activeWorkspaceID ? Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(activeWorkspaceID)) : Navigation.navigate(ROUTES.ALL_SETTINGS), - ) - } - role={CONST.ROLE.BUTTON} - accessibilityLabel={translate('common.settings')} - wrapperStyle={styles.flexGrow1} - style={styles.bottomTabBarItem} - > - - - {shouldShowWorkspaceRedBrickRoad && } - - - + + + ); } diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 941cdb2f06439..fe659dce14f38 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -28,7 +28,9 @@ import * as CurrencyUtils from '@libs/CurrencyUtils'; import {translatableTextPropTypes} from '@libs/Localize'; import getTopmostSettingsCentralPaneName from '@libs/Navigation/getTopmostSettingsCentralPaneName'; import Navigation from '@libs/Navigation/Navigation'; +import shouldShowSubscriptionsMenu from '@libs/shouldShowSubscriptionsMenu'; import * as UserUtils from '@libs/UserUtils'; +import {hasGlobalWorkspaceSettingsRBR} from '@libs/WorkspacesSettingsUtils'; import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes'; import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import * as Link from '@userActions/Link'; @@ -76,6 +78,13 @@ const propTypes = { }), ), + /** The policies which the user has access to */ + // eslint-disable-next-line react/forbid-prop-types + policies: PropTypes.object, + + // eslint-disable-next-line react/forbid-prop-types + policyMembers: PropTypes.object, + ...withLocalizePropTypes, ...withCurrentUserPersonalDetailsPropTypes, }; @@ -211,7 +220,7 @@ function InitialSettingsPage(props) { * Retuns a list of menu items data for general section * @returns {Object} object with translationKey, style and items for the general section */ - const generaltMenuItemsData = useMemo( + const generalMenuItemsData = useMemo( () => ({ sectionStyle: { ...styles.pt4, @@ -238,6 +247,52 @@ function InitialSettingsPage(props) { [styles.pt4], ); + const workspaceMenuItemsData = useMemo( + () => ({ + sectionStyle: { + ...styles.pt4, + }, + sectionTranslationKey: 'initialSettingsPage.workspaces', + items: [ + { + translationKey: 'common.workspaces', + icon: Expensicons.Building, + action: () => { + waitForNavigate(() => { + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); + })(); + }, + brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(props.policies, props.policyMembers) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + }, + ...(shouldShowSubscriptionsMenu + ? [ + { + translationKey: 'allSettingsScreen.subscriptions', + icon: Expensicons.MoneyBag, + action: () => { + Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL); + }, + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL), + }, + ] + : []), + { + translationKey: 'allSettingsScreen.cardsAndDomains', + icon: Expensicons.CardsAndDomains, + action: () => { + Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL); + }, + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL), + }, + ], + }), + [props.policies, props.policyMembers, styles.pt4, waitForNavigate], + ); + /** * Retuns JSX.Element with menu items * @param {Object} menuItemsData list with menu items data @@ -320,7 +375,8 @@ function InitialSettingsPage(props) { ); const accountMenuItems = useMemo(() => getMenuItemsSection(accountMenuItemsData), [accountMenuItemsData, getMenuItemsSection]); - const generalMenuItems = useMemo(() => getMenuItemsSection(generaltMenuItemsData), [generaltMenuItemsData, getMenuItemsSection]); + const generalMenuItems = useMemo(() => getMenuItemsSection(generalMenuItemsData), [generalMenuItemsData, getMenuItemsSection]); + const workspaceMenuItems = useMemo(() => getMenuItemsSection(workspaceMenuItemsData), [workspaceMenuItemsData, getMenuItemsSection]); const currentUserDetails = props.currentUserPersonalDetails || {}; const avatarURL = lodashGet(currentUserDetails, 'avatar', ''); @@ -386,6 +442,7 @@ function InitialSettingsPage(props) { {accountMenuItems} {generalMenuItems} + {workspaceMenuItems} Date: Wed, 21 Feb 2024 15:37:09 +0100 Subject: [PATCH 03/46] Move account settings to BottomTab --- .../Navigation/AppNavigator/AuthScreens.tsx | 9 ++- .../AppNavigator/ModalStackNavigators.tsx | 22 +++--- .../Navigators/BottomTabNavigator.tsx | 11 +-- .../BaseCentralPaneNavigator.tsx | 21 ++++- .../Navigators/FullScreenNavigator.tsx | 3 + .../createCustomBottomTabNavigator/index.tsx | 4 - .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 9 ++- src/libs/Navigation/linkingConfig/config.ts | 78 ++++++++++++------- .../linkingConfig/getAdaptedStateFromPath.ts | 10 +-- src/libs/Navigation/types.ts | 26 ++++--- .../SidebarScreen/BaseSidebarScreen.js | 20 +++-- src/pages/settings/InitialSettingsPage.js | 36 ++++----- 12 files changed, 149 insertions(+), 100 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 00c96d4364966..4b5a390978122 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -340,11 +340,11 @@ function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = f component={RightModalNavigator} listeners={modalScreenListeners} /> - + /> */} + {/* */} ); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index f6ba0609edccd..3cf407214357c 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -186,16 +186,16 @@ const NewTeachersUniteNavigator = createModalStackNavigator require('../../../pages/TeachersUnite/ImTeacherPage').default as React.ComponentType, }); -const AccountSettingsModalStackNavigator = createModalStackNavigator( - { - [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, - [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, - [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, - [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, - [SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, - }, - (styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}), -); +// const AccountSettingsModalStackNavigator = createModalStackNavigator( +// { +// [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, +// [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, +// [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, +// [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, +// [SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, +// }, +// (styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}), +// ); const WorkspaceSwitcherModalStackNavigator = createModalStackNavigator({ [SCREENS.WORKSPACE_SWITCHER.ROOT]: () => require('../../../pages/WorkspaceSwitcherPage').default as React.ComponentType, @@ -298,7 +298,7 @@ const ProcessMoneyRequestHoldStackNavigator = createModalStackNavigator({ }); export { - AccountSettingsModalStackNavigator, + // AccountSettingsModalStackNavigator, AddPersonalBankAccountModalStackNavigator, DetailsModalStackNavigator, OnboardEngagementModalStackNavigator, diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index ce03a8d5bcba9..9b71b96b909a8 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -4,12 +4,12 @@ import React from 'react'; import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator'; import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; import type {BottomTabNavigatorParamList} from '@libs/Navigation/types'; -import AllSettingsScreen from '@pages/home/sidebar/AllSettingsScreen'; import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; import SCREENS from '@src/SCREENS'; import ActiveRouteContext from './ActiveRouteContext'; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; +const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default as React.ComponentType; const Tab = createCustomBottomTabNavigator(); @@ -23,14 +23,15 @@ function BottomTabNavigator() { return ( + - require('../../../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, } satisfies Screens; +const settingsScreens = { + [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, + [SCREENS.SETTINGS.SECURITY]: () => require('../../../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, + [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, + [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, + [SCREENS.SETTINGS.ABOUT]: () => require('../../../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, +}; + function BaseCentralPaneNavigator() { const styles = useThemeStyles(); const options = { @@ -41,7 +49,18 @@ function BaseCentralPaneNavigator() { initialParams={{openOnAdminRoom: openOnAdminRoom === 'true' || undefined}} component={ReportScreenWrapper} /> - + {/* */} + {Object.entries(settingsScreens).map(([screenName, componentGetter]) => ( + + ))} {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx index f5c373fa3897b..8c53027cf7135 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx @@ -5,12 +5,10 @@ import {StackView} from '@react-navigation/stack'; import React from 'react'; import {View} from 'react-native'; import ScreenWrapper from '@components/ScreenWrapper'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useThemeStyles from '@hooks/useThemeStyles'; import type {NavigationStateRoute} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import BottomTabBar from './BottomTabBar'; -import TopBar from './TopBar'; type CustomNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { initialRouteName: string; @@ -46,7 +44,6 @@ function CustomBottomTabNavigator({initialRouteName, children, screenOptions, .. const styles = useThemeStyles(); const stateToRender = getStateToRender(state); - const {activeWorkspaceID} = useActiveWorkspace(); return ( - = { [SCREENS.HOME]: [SCREENS.REPORT], - [SCREENS.ALL_SETTINGS]: [SCREENS.SETTINGS.WORKSPACES], + [SCREENS.SETTINGS.ROOT]: [ + SCREENS.SETTINGS.PROFILE.ROOT, + SCREENS.SETTINGS.PREFERENCES.ROOT, + SCREENS.SETTINGS.SECURITY, + SCREENS.SETTINGS.WALLET.ROOT, + SCREENS.SETTINGS.ABOUT, + SCREENS.SETTINGS.WORKSPACES, + ], [SCREENS.WORKSPACE.INITIAL]: [ SCREENS.WORKSPACE.PROFILE, SCREENS.WORKSPACE.CARD, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 9f5b138cbee07..54a628f098592 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -29,11 +29,13 @@ const config: LinkingOptions['config'] = { initialRouteName: SCREENS.HOME, screens: { [SCREENS.HOME]: ROUTES.HOME, - [SCREENS.ALL_SETTINGS]: ROUTES.ALL_SETTINGS, [SCREENS.WORKSPACE.INITIAL]: { path: ROUTES.WORKSPACE_INITIAL.route, exact: true, }, + [SCREENS.SETTINGS.ROOT]: { + path: ROUTES.SETTINGS, + }, }, }, @@ -61,6 +63,50 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.MEMBERS]: { path: ROUTES.WORKSPACE_MEMBERS.route, }, + [SCREENS.SETTINGS.PROFILE.ROOT]: { + path: ROUTES.SETTINGS_PROFILE, + exact: true, + }, + [SCREENS.SETTINGS.PREFERENCES.ROOT]: { + path: ROUTES.SETTINGS_PREFERENCES, + exact: true, + }, + [SCREENS.SETTINGS.SECURITY]: { + path: ROUTES.SETTINGS_SECURITY, + exact: true, + }, + [SCREENS.SETTINGS.WALLET.ROOT]: { + path: ROUTES.SETTINGS_WALLET, + exact: true, + }, + [SCREENS.SETTINGS.ABOUT]: { + path: ROUTES.SETTINGS_ABOUT, + exact: true, + }, + // [SCREENS.SETTINGS_CENTRAL_PANE]: { + // screens: { + // [SCREENS.SETTINGS.PROFILE.ROOT]: { + // path: ROUTES.SETTINGS_PROFILE, + // exact: true, + // }, + // [SCREENS.SETTINGS.PREFERENCES.ROOT]: { + // path: ROUTES.SETTINGS_PREFERENCES, + // exact: true, + // }, + // [SCREENS.SETTINGS.SECURITY]: { + // path: ROUTES.SETTINGS_SECURITY, + // exact: true, + // }, + // [SCREENS.SETTINGS.WALLET.ROOT]: { + // path: ROUTES.SETTINGS_WALLET, + // exact: true, + // }, + // [SCREENS.SETTINGS.ABOUT]: { + // path: ROUTES.SETTINGS_ABOUT, + // exact: true, + // }, + // }, + // }, }, }, [SCREENS.NOT_FOUND]: '*', @@ -492,35 +538,7 @@ const config: LinkingOptions['config'] = { }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { - screens: { - [SCREENS.SETTINGS.ROOT]: { - path: ROUTES.SETTINGS, - }, - [SCREENS.SETTINGS_CENTRAL_PANE]: { - screens: { - [SCREENS.SETTINGS.PROFILE.ROOT]: { - path: ROUTES.SETTINGS_PROFILE, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.ROOT]: { - path: ROUTES.SETTINGS_PREFERENCES, - exact: true, - }, - [SCREENS.SETTINGS.SECURITY]: { - path: ROUTES.SETTINGS_SECURITY, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.ROOT]: { - path: ROUTES.SETTINGS_WALLET, - exact: true, - }, - [SCREENS.SETTINGS.ABOUT]: { - path: ROUTES.SETTINGS_ABOUT, - exact: true, - }, - }, - }, - }, + screens: {}, }, }, }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 8e246d82ff72d..d56f9437e1fd9 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -124,11 +124,11 @@ function getMatchingRootRouteForRHPRoute( } // Check for FullScreenNavigator - for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { - if (RHPNames && RHPNames.includes(route.name)) { - return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); - } - } + // for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { + // if (RHPNames && RHPNames.includes(route.name)) { + // return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); + // } + // } } function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 6cfb11e880951..a79de6b13f5f3 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -74,6 +74,11 @@ type CentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.MEMBERS]: { policyID: string; }; + [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; + [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; + [SCREENS.SETTINGS.SECURITY]: undefined; + [SCREENS.SETTINGS.WALLET.ROOT]: undefined; + [SCREENS.SETTINGS.ABOUT]: undefined; }; type WorkspaceSwitcherNavigatorParamList = { @@ -440,22 +445,19 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams; }; -type SettingsCentralPaneNavigatorParamList = { - [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; - [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; - [SCREENS.SETTINGS.SECURITY]: undefined; - [SCREENS.SETTINGS.WALLET.ROOT]: undefined; - [SCREENS.SETTINGS.ABOUT]: undefined; -}; +// type SettingsCentralPaneNavigatorParamList = { +// [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; +// [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; +// [SCREENS.SETTINGS.SECURITY]: undefined; +// [SCREENS.SETTINGS.WALLET.ROOT]: undefined; +// [SCREENS.SETTINGS.ABOUT]: undefined; +// }; -type FullScreenNavigatorParamList = { - [SCREENS.SETTINGS.ROOT]: undefined; - [SCREENS.SETTINGS_CENTRAL_PANE]: NavigatorScreenParams; -}; +type FullScreenNavigatorParamList = {}; type BottomTabNavigatorParamList = { [SCREENS.HOME]: undefined; - [SCREENS.ALL_SETTINGS]: undefined; + [SCREENS.SETTINGS.ROOT]: undefined; [SCREENS.WORKSPACE.INITIAL]: undefined; }; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js index 9188a859d1754..2c2d28a0edbc1 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js @@ -1,8 +1,10 @@ import React, {useEffect} from 'react'; import {View} from 'react-native'; import ScreenWrapper from '@components/ScreenWrapper'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; +import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; @@ -19,6 +21,7 @@ const startTimer = () => { function BaseSidebarScreen(props) { const styles = useThemeStyles(); + const {activeWorkspaceID} = useActiveWorkspace(); useEffect(() => { Performance.markStart(CONST.TIMING.SIDEBAR_LOADED); Timing.start(CONST.TIMING.SIDEBAR_LOADED, true); @@ -33,13 +36,16 @@ function BaseSidebarScreen(props) { includePaddingTop={false} > {({insets}) => ( - - - + <> + + + + + )} ); diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 8e9593b6584eb..4ebee2da60f1c 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -1,8 +1,7 @@ -import {useNavigationState} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {NativeModules, View} from 'react-native'; +import {NativeModules, ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; @@ -10,17 +9,18 @@ import bankAccountPropTypes from '@components/bankAccountPropTypes'; import cardPropTypes from '@components/cardPropTypes'; import ConfirmModal from '@components/ConfirmModal'; import CurrentUserPersonalDetailsSkeletonView from '@components/CurrentUserPersonalDetailsSkeletonView'; -import HeaderPageLayout from '@components/HeaderPageLayout'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {withNetwork} from '@components/OnyxProvider'; import {PressableWithFeedback} from '@components/Pressable'; +import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useActiveRoute from '@hooks/useActiveRoute'; import useLocalize from '@hooks/useLocalize'; import useSingleExecution from '@hooks/useSingleExecution'; import useTheme from '@hooks/useTheme'; @@ -29,7 +29,6 @@ import useWaitForNavigation from '@hooks/useWaitForNavigation'; import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import {translatableTextPropTypes} from '@libs/Localize'; -import getTopmostSettingsCentralPaneName from '@libs/Navigation/getTopmostSettingsCentralPaneName'; import Navigation from '@libs/Navigation/Navigation'; import shouldShowSubscriptionsMenu from '@libs/shouldShowSubscriptionsMenu'; import * as UserUtils from '@libs/UserUtils'; @@ -45,7 +44,6 @@ import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; const propTypes = { /* Onyx Props */ @@ -112,7 +110,7 @@ function InitialSettingsPage(props) { const waitForNavigate = useWaitForNavigation(); const popoverAnchor = useRef(null); const {translate} = useLocalize(); - const activeRoute = useNavigationState(getTopmostSettingsCentralPaneName); + const activeRoute = useActiveRoute(); const emojiCode = lodashGet(props, 'currentUserPersonalDetails.status.emojiCode', ''); const [shouldShowSignoutConfirmModal, setShouldShowSignoutConfirmModal] = useState(false); @@ -257,11 +255,7 @@ function InitialSettingsPage(props) { { translationKey: 'common.workspaces', icon: Expensicons.Building, - action: () => { - waitForNavigate(() => { - Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); - })(); - }, + routeName: ROUTES.SETTINGS_WORKSPACES, brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(props.policies, props.policyMembers) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, }, ...(shouldShowSubscriptionsMenu @@ -290,7 +284,7 @@ function InitialSettingsPage(props) { }, ], }), - [props.policies, props.policyMembers, styles.pt4, waitForNavigate], + [props.policies, props.policyMembers, styles.pt4], ); /** @@ -383,7 +377,7 @@ function InitialSettingsPage(props) { const accountID = lodashGet(currentUserDetails, 'accountID', ''); const headerContent = ( - + {_.isEmpty(props.currentUserPersonalDetails) || _.isUndefined(props.currentUserPersonalDetails.displayName) ? ( ) : ( @@ -466,16 +460,14 @@ function InitialSettingsPage(props) { ); return ( - Navigation.closeFullScreen()} - backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.ROOT].backgroundColor} + - + + {headerContent} {accountMenuItems} {generalMenuItems} {workspaceMenuItems} @@ -489,8 +481,8 @@ function InitialSettingsPage(props) { onConfirm={() => signOut(true)} onCancel={() => toggleSignoutConfirmModal(false)} /> - - + + ); } From 5521a197cc703788d789ec8b512b79904f58c48a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 23 Feb 2024 12:58:57 +0100 Subject: [PATCH 04/46] Move Workspace Settings to FullStackNavigator --- src/SCREENS.ts | 1 + .../Navigation/AppNavigator/AuthScreens.tsx | 10 +- .../AppNavigator/ModalStackNavigators.tsx | 24 ++-- .../Navigators/BottomTabNavigator.tsx | 7 +- .../BaseCentralPaneNavigator.tsx | 25 ++-- .../Navigators/FullScreenNavigator.tsx | 13 +- .../CustomFullScreenRouter.tsx | 16 ++- .../createCustomFullScreenNavigator/index.tsx | 2 +- src/libs/Navigation/linkTo.ts | 2 +- .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 38 +++++- .../FULL_SCREEN_TO_RHP_MAPPING.ts | 47 ++----- .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 9 -- src/libs/Navigation/linkingConfig/config.ts | 120 +++++++++++------- .../linkingConfig/getAdaptedStateFromPath.ts | 14 +- .../getMatchingBottomTabRouteForState.ts | 6 +- .../getMatchingCentralPaneRouteForState.ts | 6 +- src/libs/Navigation/switchPolicyID.ts | 8 +- src/libs/Navigation/types.ts | 33 ++++- src/pages/workspace/WorkspaceInitialPage.tsx | 4 +- 19 files changed, 216 insertions(+), 169 deletions(-) diff --git a/src/SCREENS.ts b/src/SCREENS.ts index ee3c64e8d8049..0baedabd5dc12 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -22,6 +22,7 @@ const SCREENS = { VALIDATE_LOGIN: 'ValidateLogin', UNLINK_LOGIN: 'UnlinkLogin', SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', + WORKSPACES_CENTRAL_PANE: 'WorkspacesCentralPane', SETTINGS: { ROOT: 'Settings_Root', SHARE_CODE: 'Settings_Share_Code', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 4b5a390978122..6ab2aad6edbec 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -33,6 +33,7 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; +import * as ModalStackNavigators from './ModalStackNavigators'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; @@ -340,11 +341,11 @@ function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = f component={RightModalNavigator} listeners={modalScreenListeners} /> - {/* */} + /> - {/* */} ); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 3cf407214357c..399b0dbcee063 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -186,16 +186,18 @@ const NewTeachersUniteNavigator = createModalStackNavigator require('../../../pages/TeachersUnite/ImTeacherPage').default as React.ComponentType, }); -// const AccountSettingsModalStackNavigator = createModalStackNavigator( -// { -// [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, -// [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, -// [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, -// [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, -// [SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, -// }, -// (styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}), -// ); +const WorkspaceSettingsModalStackNavigator = createModalStackNavigator( + { + [SCREENS.WORKSPACE.PROFILE]: () => require('../../../pages/workspace/WorkspaceProfilePage').default as React.ComponentType, + [SCREENS.WORKSPACE.CARD]: () => require('../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, + [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, + [SCREENS.WORKSPACE.BILLS]: () => require('../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.INVOICES]: () => require('../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, + [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, + }, + (styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}), +); const WorkspaceSwitcherModalStackNavigator = createModalStackNavigator({ [SCREENS.WORKSPACE_SWITCHER.ROOT]: () => require('../../../pages/WorkspaceSwitcherPage').default as React.ComponentType, @@ -298,7 +300,6 @@ const ProcessMoneyRequestHoldStackNavigator = createModalStackNavigator({ }); export { - // AccountSettingsModalStackNavigator, AddPersonalBankAccountModalStackNavigator, DetailsModalStackNavigator, OnboardEngagementModalStackNavigator, @@ -327,4 +328,5 @@ export { TaskModalStackNavigator, WalletStatementStackNavigator, ProcessMoneyRequestHoldStackNavigator, + WorkspaceSettingsModalStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index 9b71b96b909a8..7d169245b2531 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -8,7 +8,6 @@ import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; import SCREENS from '@src/SCREENS'; import ActiveRouteContext from './ActiveRouteContext'; -const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default as React.ComponentType; const Tab = createCustomBottomTabNavigator(); @@ -23,7 +22,7 @@ function BottomTabNavigator() { return ( - - ); diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index 6b7f4e667b6f2..cc67a4c153bb1 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -13,18 +13,19 @@ const openOnAdminRoom = url ? new URL(url).searchParams.get('openOnAdminRoom') : type Screens = Partial React.ComponentType>>; -const workspaceSettingsScreens = { - [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, - [SCREENS.WORKSPACE.PROFILE]: () => require('../../../../../pages/workspace/WorkspaceProfilePage').default as React.ComponentType, - [SCREENS.WORKSPACE.CARD]: () => require('../../../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, - [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, - [SCREENS.WORKSPACE.BILLS]: () => require('../../../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, - [SCREENS.WORKSPACE.INVOICES]: () => require('../../../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, - [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, - [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, -} satisfies Screens; +// const workspaceSettingsScreens = { +// [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, +// [SCREENS.WORKSPACE.PROFILE]: () => require('../../../../../pages/workspace/WorkspaceProfilePage').default as React.ComponentType, +// [SCREENS.WORKSPACE.CARD]: () => require('../../../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, +// [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, +// [SCREENS.WORKSPACE.BILLS]: () => require('../../../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, +// [SCREENS.WORKSPACE.INVOICES]: () => require('../../../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, +// [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, +// [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, +// } satisfies Screens; const settingsScreens = { + [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, [SCREENS.SETTINGS.SECURITY]: () => require('../../../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, @@ -61,13 +62,13 @@ function BaseCentralPaneNavigator() { getComponent={componentGetter} /> ))} - {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( + {/* {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( - ))} + ))} */} ); } diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 90471b80e4ce3..07b069462dd19 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -8,7 +8,7 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; import SCREENS from '@src/SCREENS'; -const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default as React.ComponentType; +const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; const RootStack = createCustomFullScreenNavigator(); @@ -18,21 +18,18 @@ function FullScreenNavigator() { const {isSmallScreenWidth} = useWindowDimensions(); const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils); - // TODO: DISPLAY IN THIS NAVIGATOR WORKSPACE SETTINGS SCREENS - return null; - return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index 82403e36f3e85..e7ca16df17294 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -12,7 +12,7 @@ function adaptStateIfNecessary(state: StackState) { const isNarrowLayout = getIsNarrowLayout(); // There should always be SETTINGS.ROOT screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. - if (!isAtLeastOneInState(state, SCREENS.SETTINGS.ROOT)) { + if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line @@ -20,7 +20,9 @@ function adaptStateIfNecessary(state: StackState) { // This is necessary for ts to narrow type down to PartialState. if (state.stale === true) { // Unshift the root screen to fill left pane. - state.routes.unshift({name: SCREENS.SETTINGS.ROOT}); + state.routes.unshift({ + name: SCREENS.WORKSPACE.INITIAL, + }); } } @@ -28,19 +30,21 @@ function adaptStateIfNecessary(state: StackState) { // - SETINGS.ROOT to cover left pane. // - SETTINGS_CENTRAL_PANE to cover central pane. if (!isNarrowLayout) { - if (!isAtLeastOneInState(state, SCREENS.SETTINGS_CENTRAL_PANE)) { + if (!isAtLeastOneInState(state, SCREENS.WORKSPACES_CENTRAL_PANE)) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line - // Push the default settings central pane screen. if (state.stale === true) { state.routes.push({ - name: SCREENS.SETTINGS_CENTRAL_PANE, + name: SCREENS.WORKSPACES_CENTRAL_PANE, state: { routes: [ { - name: SCREENS.SETTINGS.PROFILE.ROOT, + name: SCREENS.WORKSPACE.PROFILE, + params: { + policyID: '867ECBA40E63CFA1', + }, }, ], }, diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx index fb7ae24947c2e..61eaa7af3cc9b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx @@ -16,7 +16,7 @@ function reduceReportRoutes(routes: Routes): Routes { const reverseRoutes = [...routes].reverse(); reverseRoutes.forEach((route) => { - if (route.name === SCREENS.SETTINGS_CENTRAL_PANE) { + if (route.name === SCREENS.WORKSPACES_CENTRAL_PANE) { // Remove all report routes except the last 3. This will improve performance. if (count < 3) { result.push(route); diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 3a4abe2251207..543af4ab73b29 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -119,7 +119,7 @@ export default function linkTo(navigation: NavigationContainerRef> = { - [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION], - [SCREENS.WORKSPACE.REIMBURSE]: [SCREENS.WORKSPACE.RATE_AND_UNIT, SCREENS.WORKSPACE.RATE_AND_UNIT_RATE, SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT], - [SCREENS.WORKSPACE.MEMBERS]: [SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE], + + [SCREENS.SETTINGS.PROFILE.ROOT]: [ + SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, + SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, + SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PROFILE.PRONOUNS, + SCREENS.SETTINGS.PROFILE.TIMEZONE, + SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT, + SCREENS.SETTINGS.PROFILE.LEGAL_NAME, + SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH, + SCREENS.SETTINGS.PROFILE.ADDRESS, + SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, + SCREENS.SETTINGS.SHARE_CODE, + ], + [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], + [SCREENS.SETTINGS.WALLET.ROOT]: [ + SCREENS.SETTINGS.WALLET.DOMAIN_CARD, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM, + SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE, + SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT, + SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS, + SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, + SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, + SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, + ], + [SCREENS.SETTINGS.SECURITY]: [SCREENS.SETTINGS.TWO_FACTOR_AUTH, SCREENS.SETTINGS.CLOSE], + [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS, SCREENS.SETTINGS.TROUBLESHOOT], }; export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index ce53d00fe70b3..4037304c325d4 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -2,40 +2,19 @@ import type {FullScreenName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { - [SCREENS.SETTINGS.PROFILE.ROOT]: [ - SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, - SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, - SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, - SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME, - SCREENS.SETTINGS.PROFILE.STATUS, - SCREENS.SETTINGS.PROFILE.PRONOUNS, - SCREENS.SETTINGS.PROFILE.TIMEZONE, - SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT, - SCREENS.SETTINGS.PROFILE.LEGAL_NAME, - SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH, - SCREENS.SETTINGS.PROFILE.ADDRESS, - SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, - SCREENS.SETTINGS.SHARE_CODE, - ], - [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], - [SCREENS.SETTINGS.WALLET.ROOT]: [ - SCREENS.SETTINGS.WALLET.DOMAIN_CARD, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM, - SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE, - SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT, - SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS, - SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, - SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, - SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, - ], - [SCREENS.SETTINGS.SECURITY]: [SCREENS.SETTINGS.TWO_FACTOR_AUTH, SCREENS.SETTINGS.CLOSE], - [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS, SCREENS.SETTINGS.TROUBLESHOOT], + [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION], + [SCREENS.WORKSPACE.REIMBURSE]: [SCREENS.WORKSPACE.RATE_AND_UNIT, SCREENS.WORKSPACE.RATE_AND_UNIT_RATE, SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT], + [SCREENS.WORKSPACE.MEMBERS]: [SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE], + // [SCREENS.WORKSPACE.INITIAL]: [ + // SCREENS.WORKSPACE.PROFILE, + // SCREENS.WORKSPACE.CARD, + // SCREENS.WORKSPACE.REIMBURSE, + // SCREENS.WORKSPACE.BILLS, + // SCREENS.WORKSPACE.INVOICES, + // SCREENS.WORKSPACE.TRAVEL, + // SCREENS.WORKSPACE.MEMBERS, + // ], + }; export default FULL_SCREEN_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts index caea236835c49..78a644ab4aee0 100755 --- a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -11,15 +11,6 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record = { SCREENS.SETTINGS.ABOUT, SCREENS.SETTINGS.WORKSPACES, ], - [SCREENS.WORKSPACE.INITIAL]: [ - SCREENS.WORKSPACE.PROFILE, - SCREENS.WORKSPACE.CARD, - SCREENS.WORKSPACE.REIMBURSE, - SCREENS.WORKSPACE.BILLS, - SCREENS.WORKSPACE.INVOICES, - SCREENS.WORKSPACE.TRAVEL, - SCREENS.WORKSPACE.MEMBERS, - ], }; const generateCentralPaneToTabMapping = (): Record => { diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 54a628f098592..384f260f84981 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -29,10 +29,6 @@ const config: LinkingOptions['config'] = { initialRouteName: SCREENS.HOME, screens: { [SCREENS.HOME]: ROUTES.HOME, - [SCREENS.WORKSPACE.INITIAL]: { - path: ROUTES.WORKSPACE_INITIAL.route, - exact: true, - }, [SCREENS.SETTINGS.ROOT]: { path: ROUTES.SETTINGS, }, @@ -42,27 +38,6 @@ const config: LinkingOptions['config'] = { [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, - - [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, - [SCREENS.WORKSPACE.PROFILE]: ROUTES.WORKSPACE_PROFILE.route, - [SCREENS.WORKSPACE.CARD]: { - path: ROUTES.WORKSPACE_CARD.route, - }, - [SCREENS.WORKSPACE.REIMBURSE]: { - path: ROUTES.WORKSPACE_REIMBURSE.route, - }, - [SCREENS.WORKSPACE.BILLS]: { - path: ROUTES.WORKSPACE_BILLS.route, - }, - [SCREENS.WORKSPACE.INVOICES]: { - path: ROUTES.WORKSPACE_INVOICES.route, - }, - [SCREENS.WORKSPACE.TRAVEL]: { - path: ROUTES.WORKSPACE_TRAVEL.route, - }, - [SCREENS.WORKSPACE.MEMBERS]: { - path: ROUTES.WORKSPACE_MEMBERS.route, - }, [SCREENS.SETTINGS.PROFILE.ROOT]: { path: ROUTES.SETTINGS_PROFILE, exact: true, @@ -83,30 +58,47 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_ABOUT, exact: true, }, - // [SCREENS.SETTINGS_CENTRAL_PANE]: { - // screens: { - // [SCREENS.SETTINGS.PROFILE.ROOT]: { - // path: ROUTES.SETTINGS_PROFILE, - // exact: true, - // }, - // [SCREENS.SETTINGS.PREFERENCES.ROOT]: { - // path: ROUTES.SETTINGS_PREFERENCES, - // exact: true, - // }, - // [SCREENS.SETTINGS.SECURITY]: { - // path: ROUTES.SETTINGS_SECURITY, - // exact: true, - // }, - // [SCREENS.SETTINGS.WALLET.ROOT]: { - // path: ROUTES.SETTINGS_WALLET, - // exact: true, - // }, - // [SCREENS.SETTINGS.ABOUT]: { - // path: ROUTES.SETTINGS_ABOUT, - // exact: true, - // }, - // }, + [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, + // [SCREENS.WORKSPACE.PROFILE]: ROUTES.WORKSPACE_PROFILE.route, + // [SCREENS.WORKSPACE.CARD]: { + // path: ROUTES.WORKSPACE_CARD.route, + // }, + // [SCREENS.WORKSPACE.REIMBURSE]: { + // path: ROUTES.WORKSPACE_REIMBURSE.route, + // }, + // [SCREENS.WORKSPACE.BILLS]: { + // path: ROUTES.WORKSPACE_BILLS.route, + // }, + // [SCREENS.WORKSPACE.INVOICES]: { + // path: ROUTES.WORKSPACE_INVOICES.route, + // }, + // [SCREENS.WORKSPACE.TRAVEL]: { + // path: ROUTES.WORKSPACE_TRAVEL.route, + // }, + // [SCREENS.WORKSPACE.MEMBERS]: { + // path: ROUTES.WORKSPACE_MEMBERS.route, + // }, + // [SCREENS.SETTINGS.PROFILE.ROOT]: { + // path: ROUTES.SETTINGS_PROFILE, + // exact: true, + // }, + // [SCREENS.SETTINGS.PREFERENCES.ROOT]: { + // path: ROUTES.SETTINGS_PREFERENCES, + // exact: true, // }, + // [SCREENS.SETTINGS.SECURITY]: { + // path: ROUTES.SETTINGS_SECURITY, + // exact: true, + // }, + // [SCREENS.SETTINGS.WALLET.ROOT]: { + // path: ROUTES.SETTINGS_WALLET, + // exact: true, + // }, + // [SCREENS.SETTINGS.ABOUT]: { + // path: ROUTES.SETTINGS_ABOUT, + // exact: true, + // }, + // }, }, [SCREENS.NOT_FOUND]: '*', @@ -538,7 +530,37 @@ const config: LinkingOptions['config'] = { }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { - screens: {}, + screens: { + [SCREENS.WORKSPACE.INITIAL]: { + path: ROUTES.WORKSPACE_INITIAL.route, + }, + [SCREENS.WORKSPACES_CENTRAL_PANE]: { + screens: { + [SCREENS.WORKSPACE.PROFILE]: { + path: ROUTES.WORKSPACE_PROFILE.route, + exact: true, + }, + [SCREENS.WORKSPACE.CARD]: { + path: ROUTES.WORKSPACE_CARD.route, + }, + [SCREENS.WORKSPACE.REIMBURSE]: { + path: ROUTES.WORKSPACE_REIMBURSE.route, + }, + [SCREENS.WORKSPACE.BILLS]: { + path: ROUTES.WORKSPACE_BILLS.route, + }, + [SCREENS.WORKSPACE.INVOICES]: { + path: ROUTES.WORKSPACE_INVOICES.route, + }, + [SCREENS.WORKSPACE.TRAVEL]: { + path: ROUTES.WORKSPACE_TRAVEL.route, + }, + [SCREENS.WORKSPACE.MEMBERS]: { + path: ROUTES.WORKSPACE_MEMBERS.route, + }, + }, + }, + }, }, }, }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index d56f9437e1fd9..646c1bb79a42e 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -73,9 +73,9 @@ function createCentralPaneNavigator(route: NavigationPartialRoute): NavigationPartialRoute { const routes = []; - routes.push({name: SCREENS.SETTINGS.ROOT}); + routes.push({name: SCREENS.WORKSPACE.INITIAL}); routes.push({ - name: SCREENS.SETTINGS_CENTRAL_PANE, + name: SCREENS.WORKSPACES_CENTRAL_PANE, state: getRoutesWithIndex([route]), }); @@ -124,11 +124,11 @@ function getMatchingRootRouteForRHPRoute( } // Check for FullScreenNavigator - // for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { - // if (RHPNames && RHPNames.includes(route.name)) { - // return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); - // } - // } + for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { + if (RHPNames && RHPNames.includes(route.name)) { + return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); + } + } } function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index ef4cd65942b01..e85e7ca950dd4 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -14,9 +14,9 @@ function getMatchingBottomTabRouteForState(state: State, pol } const tabName = CENTRAL_PANE_TO_TAB_MAPPING[topmostCentralPaneRoute.name]; - if (tabName === SCREENS.WORKSPACE.INITIAL) { - return {name: tabName, params: topmostCentralPaneRoute.params}; - } + // if (tabName === SCREENS.WORKSPACE.INITIAL) { + // return {name: tabName, params: topmostCentralPaneRoute.params}; + // } return {name: tabName, params: paramsWithPolicyID}; } diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts index 55ccca73a389a..5b3fbaeb06426 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts @@ -41,9 +41,9 @@ function getMatchingCentralPaneRouteForState(state: State): const centralPaneName = TAB_TO_CENTRAL_PANE_MAPPING[topmostBottomTabRoute.name][0]; - if (topmostBottomTabRoute.name === SCREENS.WORKSPACE.INITIAL) { - return {name: centralPaneName, params: topmostBottomTabRoute.params}; - } + // if (topmostBottomTabRoute.name === SCREENS.WORKSPACE.INITIAL) { + // return {name: centralPaneName, params: topmostBottomTabRoute.params}; + // } if (topmostBottomTabRoute.name === SCREENS.HOME) { return {name: centralPaneName, params: {reportID: getTopMostReportIDFromRHP(state)}}; diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 72a7c3e32fb40..355d7a99ee11e 100644 --- a/src/libs/Navigation/switchPolicyID.ts +++ b/src/libs/Navigation/switchPolicyID.ts @@ -134,10 +134,10 @@ export default function switchPolicyID(navigation: NavigationContainerRef; +}; type BottomTabNavigatorParamList = { [SCREENS.HOME]: undefined; [SCREENS.SETTINGS.ROOT]: undefined; - [SCREENS.WORKSPACE.INITIAL]: undefined; }; type PublicScreensParamList = { @@ -524,7 +550,7 @@ type BottomTabName = keyof BottomTabNavigatorParamList; type CentralPaneName = keyof CentralPaneNavigatorParamList; -type FullScreenName = keyof SettingsCentralPaneNavigatorParamList; +type FullScreenName = keyof WorkspacesCentralPaneNavigatorParamList; type SwitchPolicyIDParams = { policyID?: string; @@ -578,4 +604,5 @@ export type { WorkspaceSwitcherNavigatorParamList, OnboardEngagementNavigatorParamList, SwitchPolicyIDParams, + FullScreenNavigatorParamList, }; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 70d871849ee62..d03f0f7917491 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -19,7 +19,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; -import type {BottomTabNavigatorParamList} from '@navigation/types'; +import type {FullScreenNavigatorParamList} from '@navigation/types'; import * as App from '@userActions/App'; import * as Policy from '@userActions/Policy'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; @@ -47,7 +47,7 @@ type WorkspaceInitialPageOnyxProps = { reimbursementAccount: OnyxEntry; }; -type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & WorkspaceInitialPageOnyxProps & StackScreenProps; +type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & WorkspaceInitialPageOnyxProps & StackScreenProps; function dismissError(policyID: string) { Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); From a7df0da5cf2d1c2817b62bd65e38002066e31ae9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 23 Feb 2024 15:26:00 +0100 Subject: [PATCH 05/46] Refactor logic of displaying workspace settings screens --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 1 - .../CustomFullScreenRouter.tsx | 7 +++---- src/libs/Navigation/linkingConfig/config.ts | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 6ab2aad6edbec..00c96d4364966 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -33,7 +33,6 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; -import * as ModalStackNavigators from './ModalStackNavigators'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index e7ca16df17294..d2bba2b6540d1 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -1,12 +1,13 @@ import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native'; import {StackRouter} from '@react-navigation/native'; +import routes from 'tests/e2e/server/routes'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import SCREENS from '@src/SCREENS'; import type {FullScreenNavigatorRouterOptions} from './types'; type StackState = StackNavigationState | PartialState>; -const isAtLeastOneInState = (state: StackState, screenName: string): boolean => !!state.routes.find((route) => route.name === screenName); +const isAtLeastOneInState = (state: StackState, screenName: string): boolean => state.routes.some((route) => route.name === screenName); function adaptStateIfNecessary(state: StackState) { const isNarrowLayout = getIsNarrowLayout(); @@ -42,9 +43,7 @@ function adaptStateIfNecessary(state: StackState) { routes: [ { name: SCREENS.WORKSPACE.PROFILE, - params: { - policyID: '867ECBA40E63CFA1', - }, + params: state.routes[0]?.params, }, ], }, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 384f260f84981..436f347fcc7e9 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -538,7 +538,6 @@ const config: LinkingOptions['config'] = { screens: { [SCREENS.WORKSPACE.PROFILE]: { path: ROUTES.WORKSPACE_PROFILE.route, - exact: true, }, [SCREENS.WORKSPACE.CARD]: { path: ROUTES.WORKSPACE_CARD.route, From eaeede44a7d23469fabeb25aae0f8e016b52b04a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 26 Feb 2024 08:29:48 +0100 Subject: [PATCH 06/46] Refactor TopBar and WorkspaceInitialPage --- src/components/Breadcrumbs.tsx | 8 +++-- src/components/WorkspaceSwitcherButton.tsx | 10 +++--- .../createCustomBottomTabNavigator/TopBar.tsx | 30 +++++++++-------- src/pages/workspace/WorkspaceInitialPage.tsx | 33 ++++++++++++------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index 34bc3f7e30c8e..def2ea494ed9a 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; import LogoComponent from '@assets/images/expensify-wordmark.svg'; import useTheme from '@hooks/useTheme'; @@ -30,9 +30,11 @@ type BreadcrumbsProps = { /** Styles to apply to the container */ style?: StyleProp; + + secondaryBreadcrumbStyle?: StyleProp; }; -function Breadcrumbs({breadcrumbs, style}: BreadcrumbsProps) { +function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbStyle}: BreadcrumbsProps) { const theme = useTheme(); const styles = useThemeStyles(); const [primaryBreadcrumb, secondaryBreadcrumb] = breadcrumbs; @@ -68,7 +70,7 @@ function Breadcrumbs({breadcrumbs, style}: BreadcrumbsProps) { / {secondaryBreadcrumb.text} diff --git a/src/components/WorkspaceSwitcherButton.tsx b/src/components/WorkspaceSwitcherButton.tsx index 314ca685e5d63..1578edbccff45 100644 --- a/src/components/WorkspaceSwitcherButton.tsx +++ b/src/components/WorkspaceSwitcherButton.tsx @@ -17,14 +17,14 @@ type WorkspaceSwitcherButtonOnyxProps = { policy: OnyxEntry; }; -type WorkspaceSwitcherButtonProps = {activeWorkspaceID?: string} & WorkspaceSwitcherButtonOnyxProps; +type WorkspaceSwitcherButtonProps = WorkspaceSwitcherButtonOnyxProps; -function WorkspaceSwitcherButton({activeWorkspaceID, policy}: WorkspaceSwitcherButtonProps) { +function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) { const {translate} = useLocalize(); const theme = useTheme(); - + const {source, name, type} = useMemo(() => { - if (!activeWorkspaceID) { + if (!policy) { return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; } @@ -34,7 +34,7 @@ function WorkspaceSwitcherButton({activeWorkspaceID, policy}: WorkspaceSwitcherB name: policy?.name ?? '', type: CONST.ICON_TYPE_WORKSPACE, }; - }, [policy, activeWorkspaceID]); + }, [policy]); return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index c2eddca54b3f4..d97556cf3c1d4 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -35,23 +35,27 @@ function TopBar({policy}: TopBarProps) { return ( - + + - - + + + + { + // if (!policy) { + // return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; + // } + + // const avatar = policy?.avatar ? policy.avatar : getDefaultWorkspaceAvatar(policy?.name); + // return { + // source: avatar, + // name: policy?.name ?? '', + // type: CONST.ICON_TYPE_WORKSPACE, + // }; + // }, [policy]); + return ( - + Date: Mon, 26 Feb 2024 12:24:36 +0100 Subject: [PATCH 07/46] Add isSelected prop to Avatar in the BottomTab --- src/components/AvatarWithIndicator.tsx | 6 ++--- .../BottomTabBar.tsx | 6 ++--- .../home/sidebar/AvatarWithOptionalStatus.js | 10 +++++-- .../sidebar/PressableAvatarWithIndicator.js | 26 ++++++++++++++----- .../SignInOrAvatarWithOptionalStatus.js | 13 ++++++++-- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index 2fd733d4b072a..9f2473ef34234 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {View} from 'react-native'; -import useThemeStyles from '@hooks/useThemeStyles'; import * as UserUtils from '@libs/UserUtils'; +import CONST from '@src/CONST'; import Avatar from './Avatar'; import AvatarSkeleton from './AvatarSkeleton'; import * as Expensicons from './Icon/Expensicons'; @@ -23,16 +23,16 @@ type AvatarWithIndicatorProps = { }; function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) { - const styles = useThemeStyles(); return ( - + {isLoading ? ( ) : ( <> diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 4092893470c38..c210cd9c258b9 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -75,7 +75,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps }} role={CONST.ROLE.BUTTON} accessibilityLabel={translate('common.chats')} - wrapperStyle={styles.flexGrow1} + wrapperStyle={styles.flex1} style={styles.bottomTabBarItem} > @@ -92,8 +92,8 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - - + + ); diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js index e1ff3982a0ccc..ed6ddaa7c0203 100644 --- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js @@ -18,14 +18,17 @@ const propTypes = { /** Emoji status */ emojiStatus: PropTypes.string, + + isSelected: PropTypes.bool, }; const defaultProps = { isCreateMenuOpen: false, emojiStatus: '', + isSelected: false, }; -function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen}) { +function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen, isSelected}) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -41,7 +44,10 @@ function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen}) { return ( - + { if (isCreateMenuOpen) { @@ -49,6 +57,8 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta Navigation.navigate(ROUTES.SETTINGS); }, [isCreateMenuOpen]); + const buttonStyle = isSelected ? {borderWidth: 2, borderRadius: 30, borderColor: theme.splashBG} : {}; + return ( - + + + ); diff --git a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js b/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js index 0ea6195cd7136..17d732a8080fa 100644 --- a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js @@ -11,13 +11,16 @@ import SignInButton from './SignInButton'; const propTypes = { /** Whether the create menu is open or not */ isCreateMenuOpen: PropTypes.bool, + + isSelected: PropTypes.bool, }; const defaultProps = { isCreateMenuOpen: false, + isSelected: false, }; -function SignInOrAvatarWithOptionalStatus({isCreateMenuOpen}) { +function SignInOrAvatarWithOptionalStatus({isCreateMenuOpen, isSelected}) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = lodashGet(currentUserPersonalDetails, 'status.emojiCode', ''); @@ -29,10 +32,16 @@ function SignInOrAvatarWithOptionalStatus({isCreateMenuOpen}) { ); } - return ; + return ( + + ); } SignInOrAvatarWithOptionalStatus.propTypes = propTypes; From 7229f637e70fb4b09cbb04e8203f871f03c95727 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 26 Feb 2024 12:38:58 +0100 Subject: [PATCH 08/46] Refactor InitialSettingsPage --- src/pages/settings/InitialSettingsPage.js | 137 +++++++++++----------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 4ebee2da60f1c..88dcf570d8006 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -173,77 +173,11 @@ function InitialSettingsPage(props) { icon: Expensicons.Lock, routeName: ROUTES.SETTINGS_SECURITY, }, - { - translationKey: 'initialSettingsPage.goToExpensifyClassic', - icon: Expensicons.ExpensifyLogoNew, - action: () => { - Link.openOldDotLink(CONST.OLDDOT_URLS.INBOX); - }, - link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.INBOX), - iconRight: Expensicons.NewWindow, - shouldShowRightIcon: true, - }, - { - translationKey: 'initialSettingsPage.signOut', - icon: Expensicons.Exit, - action: () => { - signOut(false); - }, - }, ], }; - if (NativeModules.HybridAppModule) { - const hybridAppMenuItems = _.filter( - [ - { - translationKey: 'initialSettingsPage.returnToClassic', - icon: Expensicons.RotateLeft, - shouldShowRightIcon: true, - iconRight: Expensicons.NewWindow, - action: () => NativeModules.HybridAppModule.closeReactNativeApp(), - }, - ...defaultMenu.items, - ], - (item) => item.translationKey !== 'initialSettingsPage.signOut' && item.translationKey !== 'initialSettingsPage.goToExpensifyClassic', - ); - - return {sectionStyle: styles.accountSettingsSectionContainer, sectionTranslationKey: 'initialSettingsPage.account', items: hybridAppMenuItems}; - } - return defaultMenu; - }, [props.bankAccountList, props.fundList, props.loginList, props.userWallet.errors, props.walletTerms.errors, signOut, styles.accountSettingsSectionContainer]); - - /** - * Retuns a list of menu items data for general section - * @returns {Object} object with translationKey, style and items for the general section - */ - const generalMenuItemsData = useMemo( - () => ({ - sectionStyle: { - ...styles.pt4, - }, - sectionTranslationKey: 'initialSettingsPage.general', - items: [ - { - translationKey: 'initialSettingsPage.help', - icon: Expensicons.QuestionMark, - action: () => { - Link.openExternalLink(CONST.NEWHELP_URL); - }, - iconRight: Expensicons.NewWindow, - shouldShowRightIcon: true, - link: CONST.NEWHELP_URL, - }, - { - translationKey: 'initialSettingsPage.about', - icon: Expensicons.Info, - routeName: ROUTES.SETTINGS_ABOUT, - }, - ], - }), - [styles.pt4], - ); + }, [props.bankAccountList, props.fundList, props.loginList, props.userWallet.errors, props.walletTerms.errors, styles.accountSettingsSectionContainer]); const workspaceMenuItemsData = useMemo( () => ({ @@ -287,6 +221,73 @@ function InitialSettingsPage(props) { [props.policies, props.policyMembers, styles.pt4], ); + /** + * Retuns a list of menu items data for general section + * @returns {Object} object with translationKey, style and items for the general section + */ + const generalMenuItemsData = useMemo(() => { + const defaultMenu = [ + { + translationKey: 'initialSettingsPage.goToExpensifyClassic', + icon: Expensicons.ExpensifyLogoNew, + action: () => { + Link.openOldDotLink(CONST.OLDDOT_URLS.INBOX); + }, + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.INBOX), + iconRight: Expensicons.NewWindow, + shouldShowRightIcon: true, + }, + { + translationKey: 'initialSettingsPage.help', + icon: Expensicons.QuestionMark, + action: () => { + Link.openExternalLink(CONST.NEWHELP_URL); + }, + iconRight: Expensicons.NewWindow, + shouldShowRightIcon: true, + link: CONST.NEWHELP_URL, + }, + { + translationKey: 'initialSettingsPage.about', + icon: Expensicons.Info, + routeName: ROUTES.SETTINGS_ABOUT, + }, + { + translationKey: 'initialSettingsPage.signOut', + icon: Expensicons.Exit, + action: () => { + signOut(false); + }, + }, + ]; + + if (NativeModules.HybridAppModule) { + const hybridAppMenuItems = _.filter( + [ + { + translationKey: 'initialSettingsPage.returnToClassic', + icon: Expensicons.RotateLeft, + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + action: () => NativeModules.HybridAppModule.closeReactNativeApp(), + }, + ...defaultMenu.items, + ], + (item) => item.translationKey !== 'initialSettingsPage.signOut' && item.translationKey !== 'initialSettingsPage.goToExpensifyClassic', + ); + + return {sectionStyle: styles.accountSettingsSectionContainer, sectionTranslationKey: 'initialSettingsPage.general', items: hybridAppMenuItems}; + } + + return { + sectionStyle: { + ...styles.pt4, + }, + sectionTranslationKey: 'initialSettingsPage.general', + items: defaultMenu, + }; + }, [styles.pt4, styles.accountSettingsSectionContainer, signOut]); + /** * Retuns JSX.Element with menu items * @param {Object} menuItemsData list with menu items data @@ -469,8 +470,8 @@ function InitialSettingsPage(props) { {headerContent} {accountMenuItems} - {generalMenuItems} {workspaceMenuItems} + {generalMenuItems} Date: Mon, 26 Feb 2024 14:19:49 +0100 Subject: [PATCH 09/46] Handle displaying WorkspaceInitialPage in FullScreenNavigator --- .../@react-navigation+stack+6.3.16+002+dontDetachScreen.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch index 877521094cd4f..c65ebbb980073 100644 --- a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Settings_Root') && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Workspace_Initial') && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, From 6a6b39649e2d26a5794d3b2f9cb266883d82d9c5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 26 Feb 2024 16:19:02 +0100 Subject: [PATCH 10/46] Add fixes to FullScreenNavigator --- .../CustomFullScreenRouter.tsx | 3 ++- ...e.ts => getTopmostWorkspacesCentralPaneName.ts} | 6 +++--- src/libs/Navigation/linkTo.ts | 1 - .../linkingConfig/customGetPathFromState.ts | 1 - .../linkingConfig/getAdaptedStateFromPath.ts | 14 +++++--------- src/libs/Navigation/types.ts | 4 +++- src/pages/settings/InitialSettingsPage.js | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 5 +++-- 8 files changed, 17 insertions(+), 19 deletions(-) rename src/libs/Navigation/{getTopmostSettingsCentralPaneName.ts => getTopmostWorkspacesCentralPaneName.ts} (76%) diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index d2bba2b6540d1..04967db27c201 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -1,6 +1,5 @@ import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native'; import {StackRouter} from '@react-navigation/native'; -import routes from 'tests/e2e/server/routes'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import SCREENS from '@src/SCREENS'; import type {FullScreenNavigatorRouterOptions} from './types'; @@ -11,6 +10,7 @@ const isAtLeastOneInState = (state: StackState, screenName: string): boolean => function adaptStateIfNecessary(state: StackState) { const isNarrowLayout = getIsNarrowLayout(); + const topmostWorkspaceCentralPaneRoute = state.routes.at(-1)?.state?.routes[0]; // There should always be SETTINGS.ROOT screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) { @@ -23,6 +23,7 @@ function adaptStateIfNecessary(state: StackState) { // Unshift the root screen to fill left pane. state.routes.unshift({ name: SCREENS.WORKSPACE.INITIAL, + params: topmostWorkspaceCentralPaneRoute?.params, }); } } diff --git a/src/libs/Navigation/getTopmostSettingsCentralPaneName.ts b/src/libs/Navigation/getTopmostWorkspacesCentralPaneName.ts similarity index 76% rename from src/libs/Navigation/getTopmostSettingsCentralPaneName.ts rename to src/libs/Navigation/getTopmostWorkspacesCentralPaneName.ts index 0ddea6588ef63..db11368c13456 100644 --- a/src/libs/Navigation/getTopmostSettingsCentralPaneName.ts +++ b/src/libs/Navigation/getTopmostWorkspacesCentralPaneName.ts @@ -2,12 +2,12 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import SCREENS from '@src/SCREENS'; // Get the name of topmost report in the navigation stack. -function getTopmostSettingsCentralPaneName(state: NavigationState | PartialState): string | undefined { +function getTopmostWorkspacesCentralPaneName(state: NavigationState | PartialState): string | undefined { if (!state) { return; } - const topmostCentralPane = state.routes.filter((route) => typeof route !== 'number' && 'name' in route && route.name === SCREENS.SETTINGS_CENTRAL_PANE).at(-1); + const topmostCentralPane = state.routes.filter((route) => typeof route !== 'number' && 'name' in route && route.name === SCREENS.WORKSPACES_CENTRAL_PANE).at(-1); if (!topmostCentralPane) { return; @@ -24,4 +24,4 @@ function getTopmostSettingsCentralPaneName(state: NavigationState | PartialState return topmostCentralPane.state?.routes.at(-1)?.name; } -export default getTopmostSettingsCentralPaneName; +export default getTopmostWorkspacesCentralPaneName; diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 4de90c2e15591..b476087fa9d09 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -119,7 +119,6 @@ export default function linkTo(navigation: NavigationContainerRef) => { const customGetPathFromState: typeof getPathFromState = (state, options) => { const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); - // For the Home page we should remove policyID from the params, const path = getPathFromState(stateWithoutPolicyID, options); const policyIDFromState = getPolicyIDFromState(state as State); diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 827f079239656..384c30e2c2efe 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -70,10 +70,10 @@ function createCentralPaneNavigator(route: NavigationPartialRoute): NavigationPartialRoute { +function createFullScreenNavigator(route?: NavigationPartialRoute, policyID?: string): NavigationPartialRoute { const routes = []; - routes.push({name: SCREENS.WORKSPACE.INITIAL}); + routes.push({name: SCREENS.WORKSPACE.INITIAL, params: {policyID}}); if (route) { routes.push({ name: SCREENS.WORKSPACES_CENTRAL_PANE, @@ -89,6 +89,7 @@ function createFullScreenNavigator(route?: NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { @@ -127,14 +128,9 @@ function getMatchingRootRouteForRHPRoute( // Check for FullScreenNavigator for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { if (RHPNames && RHPNames.includes(route.name)) { - return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); + return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}, policyID); } } - - // This screen is opened from the LHN of the FullStackNavigator, so in this case we shouldn't push any CentralPane screen - if (route.name === SCREENS.SETTINGS.SHARE_CODE) { - return createFullScreenNavigator(); - } } function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { @@ -161,7 +157,7 @@ function getAdaptedState(state: PartialState const routes = []; if (topmostNestedRHPRoute) { - let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute); + let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute, policyID); // This may happen if this RHP doens't have a route that should be under the overlay defined. if (!matchingRootRoute) { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 7b13aa10f438c..7180260899d03 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -479,7 +479,9 @@ type WorkspacesCentralPaneNavigatorParamList = { }; type FullScreenNavigatorParamList = { - [SCREENS.WORKSPACE.INITIAL]: undefined; + [SCREENS.WORKSPACE.INITIAL]: { + policyID: string; + }; [SCREENS.WORKSPACES_CENTRAL_PANE]: NavigatorScreenParams; }; diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 88dcf570d8006..1e9f54e6afba8 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -271,7 +271,7 @@ function InitialSettingsPage(props) { iconRight: Expensicons.NewWindow, action: () => NativeModules.HybridAppModule.closeReactNativeApp(), }, - ...defaultMenu.items, + ...defaultMenu, ], (item) => item.translationKey !== 'initialSettingsPage.signOut' && item.translationKey !== 'initialSettingsPage.goToExpensifyClassic', ); diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 5aec95aa86422..63abb971a4863 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -1,3 +1,4 @@ +import {useNavigationState} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ScrollView, View} from 'react-native'; @@ -18,6 +19,7 @@ import usePrevious from '@hooks/usePrevious'; import useSingleExecution from '@hooks/useSingleExecution'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; +import getTopmostWorkspacesCentralPaneName from '@libs/Navigation/getTopmostWorkspacesCentralPaneName'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; @@ -63,8 +65,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r const hasPolicyCreationError = !!(policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && policy.errors); const waitForNavigate = useWaitForNavigation(); const {singleExecution, isExecuting} = useSingleExecution(); - const activeRoute = useActiveRoute(); - + const activeRoute = useNavigationState(getTopmostWorkspacesCentralPaneName); const {translate} = useLocalize(); const policyID = policy?.id ?? ''; From 3b1de43b08989e405698c2c7e411b9fa83f7b41e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 26 Feb 2024 17:07:45 +0100 Subject: [PATCH 11/46] Add policyAvatar to HeaderWithBackButton --- src/components/HeaderWithBackButton/index.tsx | 10 ++++++++ src/components/HeaderWithBackButton/types.ts | 4 ++++ src/pages/workspace/WorkspaceInitialPage.tsx | 23 ++++++++++--------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 97e915d47b221..0e2a5aeaf0865 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {Keyboard, StyleSheet, View} from 'react-native'; +import Avatar from '@components/Avatar'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; import Icon from '@components/Icon'; @@ -32,6 +33,7 @@ function HeaderWithBackButton({ onThreeDotsButtonPress = () => {}, report = null, policy, + policyAvatar, shouldShowAvatarWithDisplay = false, shouldShowBackButton = true, shouldShowBorderBottom = false, @@ -118,6 +120,14 @@ function HeaderWithBackButton({ additionalStyles={[styles.mr2]} /> )} + {policyAvatar && ( + + )} {shouldShowAvatarWithDisplay ? ( & { /** Whether we should overlay the 3 dots menu */ shouldOverlayDots?: boolean; + + policyAvatar?: Icon; }; export type {ThreeDotsMenuItem}; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 63abb971a4863..31d1b9e7faf5b 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -189,18 +189,18 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r // We check isPendingDelete for both policy and prevPolicy to prevent the NotFound view from showing right after we delete the workspace (PolicyUtils.isPendingDeletePolicy(policy) && PolicyUtils.isPendingDeletePolicy(prevPolicy)); - // const policyAvatar = useMemo(() => { - // if (!policy) { - // return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; - // } + const policyAvatar = useMemo(() => { + if (!policy) { + return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; + } - // const avatar = policy?.avatar ? policy.avatar : getDefaultWorkspaceAvatar(policy?.name); - // return { - // source: avatar, - // name: policy?.name ?? '', - // type: CONST.ICON_TYPE_WORKSPACE, - // }; - // }, [policy]); + const avatar = policy?.avatar ? policy.avatar : getDefaultWorkspaceAvatar(policy?.name); + return { + source: avatar, + name: policy?.name ?? '', + type: CONST.ICON_TYPE_WORKSPACE, + }; + }, [policy]); return ( From 8d2bf343675ec1cf6a2c9a3edea9db0125780d29 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 27 Feb 2024 15:58:16 +0100 Subject: [PATCH 12/46] Refactor logic of the BottomTabNavigator --- .../Navigators/BottomTabNavigator.tsx | 9 ++-- .../BottomTabBar.tsx | 8 ++-- .../AppNavigator/getPartialStateDiff.ts | 2 +- src/libs/Navigation/NavigationRoot.tsx | 2 +- src/libs/Navigation/linkTo.ts | 3 +- .../linkingConfig/customGetPathFromState.ts | 6 +-- .../linkingConfig/getAdaptedStateFromPath.ts | 1 - .../getMatchingCentralPaneRouteForState.ts | 48 +++++++++---------- src/libs/Navigation/switchPolicyID.ts | 9 ++-- src/pages/workspace/WorkspaceInitialPage.tsx | 3 +- .../workspace/WorkspacePageWithSections.tsx | 2 +- 11 files changed, 44 insertions(+), 49 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index 7d169245b2531..dc0fe12f49288 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -19,18 +19,19 @@ const screenOptions: StackNavigationOptions = { function BottomTabNavigator() { const activeRoute = useNavigationState(getTopmostCentralPaneRoute); + return ( + - ); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index c210cd9c258b9..b36d50869f7cd 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -42,12 +42,14 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps const navigationState = navigation.getState(); const routes = navigationState.routes; const currentRoute = routes[navigationState.index]; - const bottomTabRoute = getTopmostBottomTabRoute(navigationState); + if ( // When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method. // To prevent this, the value of the bottomTabRoute?.name is checked here - bottomTabRoute?.name === SCREENS.WORKSPACE.INITIAL || - (currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) + // bottomTabRoute?.name === SCREENS.WORKSPACE.INITIAL || + currentRoute && + currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && + currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR ) { return; } diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts index b0825b4b29914..20d9b21ec2352 100644 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts @@ -40,7 +40,7 @@ type GetPartialStateDiffReturnType = { * @param metainfo - Additional info from getAdaptedStateFromPath function. * @returns The screen options object */ -function getPartialStateDiff(state: State, templateState: State, metainfo: Metainfo): GetPartialStateDiffReturnType { +function getPartialStateDiff(state: State, templateState: State, metainfo: Metainfo): GetPartialStateDiffReturnType { const diff: GetPartialStateDiffReturnType = {}; // If it is mandatory we need to compare both central pane and bottom tab of states. diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 20c426a74c719..21e404427285e 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -87,7 +87,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N // eslint-disable-next-line react-hooks/exhaustive-deps [], ); - + // https://reactnavigation.org/docs/themes const navigationTheme = useMemo( () => ({ diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index b476087fa9d09..46354a2ec2dac 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -136,9 +136,8 @@ export default function linkTo(navigation: NavigationContainerRef)?.name === SCREENS.WORKSPACE.INITIAL && path.includes('workspace'); - if (policyID && !isWorkspaceSettingsOpened) { + if (policyID) { // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. // We need to replace the path in the state with the proper one. // To avoid this hacky solution we may want to create custom getActionFromState function in the future. diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 32d81f272d4a2..ffe1cd82085fe 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -15,12 +15,10 @@ const removePolicyIDParamFromState = (state: State) => { }; const customGetPathFromState: typeof getPathFromState = (state, options) => { - const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); // For the Home page we should remove policyID from the params, - const path = getPathFromState(stateWithoutPolicyID, options); + const path = getPathFromState(state, options); const policyIDFromState = getPolicyIDFromState(state as State); - const isWorkspaceSettingsOpened = getTopmostBottomTabRoute(state as State)?.name === SCREENS.WORKSPACE.INITIAL && path.includes('workspace'); - return `${policyIDFromState && !isWorkspaceSettingsOpened ? `/w/${policyIDFromState}` : ''}${path}`; + return `${policyIDFromState ? `/w/${policyIDFromState}` : ''}${path}`; }; export default customGetPathFromState; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 384c30e2c2efe..7812a2c821aaa 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -291,7 +291,6 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options) => { const state = getStateFromPath(pathWithoutPolicyID, options) as PartialState>; replacePathInNestedState(state, path); - if (state === undefined) { throw new Error('Unable to parse path'); } diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts index bf9a9f0110721..3b76c823675b7 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts @@ -4,8 +4,6 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING'; -// const WORKSPACES_SCREENS = TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.WORKSPACE.INITIAL].concat(TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.ALL_SETTINGS]); - /** * @param state - react-navigation state */ @@ -50,27 +48,27 @@ function hasRouteMatchingPolicyID(route: NavigationPartialRoute } // Get already opened settings screen within the policy -// function getAlreadyOpenedSettingsScreen(rootState?: State, policyID?: string): keyof CentralPaneNavigatorParamList | undefined { -// if (!rootState) { -// return undefined; -// } +function getAlreadyOpenedSettingsScreen(rootState?: State, policyID?: string): keyof CentralPaneNavigatorParamList | undefined { + if (!rootState) { + return undefined; + } -// // If one of the screen from WORKSPACES_SCREENS is now in the navigation state, we can decide which screen we should display. -// // A screen from the navigation state can be pushed to the navigation state again only if it has a matching policyID with the currently selected workspace. -// // Otherwise, when we switch the workspace, we want to display the initial screen in the settings tab. -// const alreadyOpenedSettingsTab = rootState.routes -// .filter((item) => item.params && 'screen' in item.params && WORKSPACES_SCREENS.includes(item.params.screen as keyof CentralPaneNavigatorParamList)) -// .at(-1); + // If one of the screen from TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.SETTINGS.ROOT] is now in the navigation state, we can decide which screen we should display. + // A screen from the navigation state can be pushed to the navigation state again only if it has a matching policyID with the currently selected workspace. + // Otherwise, when we switch the workspace, we want to display the initial screen in the settings tab. + const alreadyOpenedSettingsTab = rootState.routes + .filter((item) => item.params && 'screen' in item.params && TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.SETTINGS.ROOT].includes(item.params.screen as keyof CentralPaneNavigatorParamList)) + .at(-1); -// if (!hasRouteMatchingPolicyID(alreadyOpenedSettingsTab as NavigationPartialRoute, policyID)) { -// return undefined; -// } + if (!hasRouteMatchingPolicyID(alreadyOpenedSettingsTab as NavigationPartialRoute, policyID)) { + return undefined; + } -// const settingsScreen = -// alreadyOpenedSettingsTab?.params && 'screen' in alreadyOpenedSettingsTab?.params ? (alreadyOpenedSettingsTab?.params?.screen as keyof CentralPaneNavigatorParamList) : undefined; + const settingsScreen = + alreadyOpenedSettingsTab?.params && 'screen' in alreadyOpenedSettingsTab?.params ? (alreadyOpenedSettingsTab?.params?.screen as keyof CentralPaneNavigatorParamList) : undefined; -// return settingsScreen; -// } + return settingsScreen; +} // Get matching central pane route for bottom tab navigator. e.g HOME -> REPORT function getMatchingCentralPaneRouteForState(state: State, rootState?: State): NavigationPartialRoute | undefined { @@ -82,12 +80,12 @@ function getMatchingCentralPaneRouteForState(state: State, r const centralPaneName = TAB_TO_CENTRAL_PANE_MAPPING[topmostBottomTabRoute.name][0]; - // if (topmostBottomTabRoute.name === SCREENS.WORKSPACE.INITIAL) { - // // When we go back to the settings tab without switching the workspace id, we want to return to the previously opened screen - // const policyID = topmostBottomTabRoute?.params && 'policyID' in topmostBottomTabRoute?.params ? (topmostBottomTabRoute.params.policyID as string) : undefined; - // const screen = getAlreadyOpenedSettingsScreen(rootState, policyID) ?? centralPaneName; - // return {name: screen, params: topmostBottomTabRoute.params}; - // } + if (topmostBottomTabRoute.name === SCREENS.SETTINGS.ROOT) { + // When we go back to the settings tab without switching the workspace id, we want to return to the previously opened screen + const policyID = topmostBottomTabRoute?.params && 'policyID' in topmostBottomTabRoute?.params ? (topmostBottomTabRoute.params.policyID as string) : undefined; + const screen = getAlreadyOpenedSettingsScreen(rootState, policyID) ?? centralPaneName; + return {name: screen, params: topmostBottomTabRoute.params}; + } if (topmostBottomTabRoute.name === SCREENS.HOME) { return {name: centralPaneName, params: {reportID: getTopMostReportIDFromRHP(state)}}; diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 355d7a99ee11e..5f4b3c5a204d1 100644 --- a/src/libs/Navigation/switchPolicyID.ts +++ b/src/libs/Navigation/switchPolicyID.ts @@ -10,7 +10,6 @@ import SCREENS from '@src/SCREENS'; import getStateFromPath from './getStateFromPath'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import linkingConfig from './linkingConfig'; -import TAB_TO_CENTRAL_PANE_MAPPING from './linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING'; import type {NavigationRoot, RootStackParamList, StackNavigationAction, State, SwitchPolicyIDParams} from './types'; type ActionPayloadParams = { @@ -110,7 +109,7 @@ export default function switchPolicyID(navigation: NavigationContainerRef); @@ -123,9 +122,9 @@ export default function switchPolicyID(navigation: NavigationContainerRef @@ -217,7 +216,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 4a77adac7b377..07725227f2e05 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -122,7 +122,7 @@ function WorkspacePageWithSections({ Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); // Needed when workspace with given policyID does not exist - Navigation.navigateWithSwitchPolicyID({route: ROUTES.ALL_SETTINGS}); + // Navigation.navigateWithSwitchPolicyID({route: ROUTES.ALL_SETTINGS}); }; useEffect(() => { From 4d9a4cb93216745cdac71c53ec1d96680d2c3e64 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 27 Feb 2024 18:06:03 +0100 Subject: [PATCH 13/46] Refactor Indicator --- src/components/Indicator.tsx | 34 +++++++++++++++++-- .../BottomTabBar.tsx | 4 +-- src/styles/index.ts | 8 ++--- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx index 1420a6abe1892..486189c66710d 100644 --- a/src/components/Indicator.tsx +++ b/src/components/Indicator.tsx @@ -1,17 +1,24 @@ import React from 'react'; import {StyleSheet, View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as PolicyUtils from '@libs/PolicyUtils'; import * as UserUtils from '@libs/UserUtils'; import * as PaymentMethods from '@userActions/PaymentMethods'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {BankAccountList, FundList, LoginList, UserWallet, WalletTerms} from '@src/types/onyx'; +import type {BankAccountList, FundList, LoginList, Policy, PolicyMembers, ReimbursementAccount, UserWallet, WalletTerms} from '@src/types/onyx'; type CheckingMethod = () => boolean; type IndicatorOnyxProps = { + /** The employee list of all policies (coming from Onyx) */ + allPolicyMembers: OnyxCollection; + + /** All the user's policies (from Onyx via withFullPolicy) */ + policies: OnyxCollection; + /** List of bank accounts */ bankAccountList: OnyxEntry; @@ -21,6 +28,9 @@ type IndicatorOnyxProps = { /** The user's wallet (coming from Onyx) */ userWallet: OnyxEntry; + /** Bank account attached to free plan */ + reimbursementAccount: OnyxEntry; + /** Information about the user accepting the terms for payments */ walletTerms: OnyxEntry; @@ -30,16 +40,25 @@ type IndicatorOnyxProps = { type IndicatorProps = IndicatorOnyxProps; -function Indicator({bankAccountList, fundList, userWallet, walletTerms, loginList}: IndicatorOnyxProps) { +function Indicator({reimbursementAccount, allPolicyMembers, policies, bankAccountList, fundList, userWallet, walletTerms, loginList}: IndicatorOnyxProps) { const theme = useTheme(); const styles = useThemeStyles(); + // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and + // those should be cleaned out before doing any error checking + const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => !!policy)); + const cleanAllPolicyMembers = Object.fromEntries(Object.entries(allPolicyMembers ?? {}).filter(([, policyMembers]) => !!policyMembers)); + // All of the error & info-checking methods are put into an array. This is so that using _.some() will return // early as soon as the first error / info condition is returned. This makes the checks very efficient since // we only care if a single error / info condition exists anywhere. const errorCheckingMethods: CheckingMethod[] = [ () => Object.keys(userWallet?.errors ?? {}).length > 0, () => PaymentMethods.hasPaymentMethodError(bankAccountList, fundList), + () => Object.values(cleanPolicies).some(PolicyUtils.hasPolicyError), + () => Object.values(cleanPolicies).some(PolicyUtils.hasCustomUnitsError), + () => Object.values(cleanAllPolicyMembers).some(PolicyUtils.hasPolicyMemberError), + () => Object.keys(reimbursementAccount?.errors ?? {}).length > 0, () => !!loginList && UserUtils.hasLoginListError(loginList), // Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead) @@ -58,9 +77,18 @@ function Indicator({bankAccountList, fundList, userWallet, walletTerms, loginLis Indicator.displayName = 'Indicator'; export default withOnyx({ + allPolicyMembers: { + key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, + }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, bankAccountList: { key: ONYXKEYS.BANK_ACCOUNT_LIST, }, + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, fundList: { key: ONYXKEYS.FUND_LIST, }, diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index b36d50869f7cd..6752bb9011066 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -64,9 +64,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps return topmostBottomTabRoute?.name ?? SCREENS.HOME; }); - const shouldShowWorkspaceRedBrickRoad = checkIfWorkspaceSettingsTabHasRBR(activeWorkspaceID) && currentTabName === SCREENS.HOME; - - const chatTabBrickRoad = currentTabName !== SCREENS.HOME ? getChatTabBrickRoad(activeWorkspaceID) : undefined; + const chatTabBrickRoad = getChatTabBrickRoad(activeWorkspaceID); return ( diff --git a/src/styles/index.ts b/src/styles/index.ts index 62d50df5ef5ee..4b6460d25e825 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1419,10 +1419,10 @@ const styles = (theme: ThemeColors) => borderRadius: 8, borderWidth: 2, position: 'absolute', - right: -2, - top: -1, - height: 16, - width: 16, + right: -4, + top: -3, + height: 12, + width: 12, zIndex: 10, } satisfies ViewStyle), From 91644b1c5823a9cfc19c1a1a290ffdf42a2bbf00 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 10:32:46 +0100 Subject: [PATCH 14/46] Run prettier --- src/components/AvatarWithIndicator.tsx | 1 - src/components/WorkspaceSwitcherButton.tsx | 2 +- src/libs/Navigation/AppNavigator/getPartialStateDiff.ts | 2 +- src/libs/Navigation/NavigationRoot.tsx | 2 +- src/libs/Navigation/linkTo.ts | 2 -- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index 9f2473ef34234..4fde0be5bf246 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -23,7 +23,6 @@ type AvatarWithIndicatorProps = { }; function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) { - return ( diff --git a/src/components/WorkspaceSwitcherButton.tsx b/src/components/WorkspaceSwitcherButton.tsx index 1578edbccff45..a94f54682c852 100644 --- a/src/components/WorkspaceSwitcherButton.tsx +++ b/src/components/WorkspaceSwitcherButton.tsx @@ -22,7 +22,7 @@ type WorkspaceSwitcherButtonProps = WorkspaceSwitcherButtonOnyxProps; function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) { const {translate} = useLocalize(); const theme = useTheme(); - + const {source, name, type} = useMemo(() => { if (!policy) { return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts index 20d9b21ec2352..b0825b4b29914 100644 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts @@ -40,7 +40,7 @@ type GetPartialStateDiffReturnType = { * @param metainfo - Additional info from getAdaptedStateFromPath function. * @returns The screen options object */ -function getPartialStateDiff(state: State, templateState: State, metainfo: Metainfo): GetPartialStateDiffReturnType { +function getPartialStateDiff(state: State, templateState: State, metainfo: Metainfo): GetPartialStateDiffReturnType { const diff: GetPartialStateDiffReturnType = {}; // If it is mandatory we need to compare both central pane and bottom tab of states. diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 21e404427285e..20c426a74c719 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -87,7 +87,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N // eslint-disable-next-line react-hooks/exhaustive-deps [], ); - + // https://reactnavigation.org/docs/themes const navigationTheme = useMemo( () => ({ diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 46354a2ec2dac..0eade256072d7 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -6,7 +6,6 @@ import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import getActionsFromPartialDiff from './AppNavigator/getActionsFromPartialDiff'; import getPartialStateDiff from './AppNavigator/getPartialStateDiff'; import dismissModal from './dismissModal'; @@ -136,7 +135,6 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 28 Feb 2024 10:33:46 +0100 Subject: [PATCH 15/46] Add navigation fixes --- .../Navigation/linkingConfig/customGetPathFromState.ts | 7 ++++--- .../Navigation/linkingConfig/getAdaptedStateFromPath.ts | 4 ++-- .../linkingConfig/getMatchingCentralPaneRouteForState.ts | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index ffe1cd82085fe..2c2140e49f7aa 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -8,15 +8,16 @@ import SCREENS from '@src/SCREENS'; const removePolicyIDParamFromState = (state: State) => { const stateCopy = _.cloneDeep(state); const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); - if (bottomTabRoute?.name === SCREENS.HOME && bottomTabRoute?.params && 'policyID' in bottomTabRoute?.params) { + if (bottomTabRoute?.name && [SCREENS.HOME, SCREENS.SETTINGS.ROOT].includes(bottomTabRoute?.name) && bottomTabRoute?.params && 'policyID' in bottomTabRoute?.params) { delete bottomTabRoute.params.policyID; } return stateCopy; }; const customGetPathFromState: typeof getPathFromState = (state, options) => { - // For the Home page we should remove policyID from the params, - const path = getPathFromState(state, options); + // For the Home and Settings pages we should remove policyID from the params, because on small screens it's displayed twice in the URL + const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); + const path = getPathFromState(stateWithoutPolicyID, options); const policyIDFromState = getPolicyIDFromState(state as State); return `${policyIDFromState ? `/w/${policyIDFromState}` : ''}${path}`; }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 7812a2c821aaa..f759c818e15c5 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -160,10 +160,10 @@ function getAdaptedState(state: PartialState let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute, policyID); // This may happen if this RHP doens't have a route that should be under the overlay defined. - if (!matchingRootRoute) { + if (!matchingRootRoute || (topmostNestedRHPRoute?.name && [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS].includes(topmostNestedRHPRoute?.name))) { metainfo.isCentralPaneAndBottomTabMandatory = false; metainfo.isFullScreenNavigatorMandatory = false; - matchingRootRoute = createCentralPaneNavigator({name: SCREENS.REPORT}); + matchingRootRoute = matchingRootRoute ?? createCentralPaneNavigator({name: SCREENS.REPORT}); } // If the root route is type of FullScreenNavigator, the default bottom tab will be added. diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts index 3b76c823675b7..e4e3b98c69a8c 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts @@ -33,7 +33,7 @@ const getTopMostReportIDFromRHP = (state: State): string => { // Check if the given route has a policyID equal to the id provided in the function params function hasRouteMatchingPolicyID(route: NavigationPartialRoute, policyID?: string) { - if (!route.params) { + if (!route?.params) { return false; } From 8e09475393893af367eb80d930d686e8cdb3f241 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 11:12:45 +0100 Subject: [PATCH 16/46] Refactor getAdaptedState --- .../linkingConfig/getAdaptedStateFromPath.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index f759c818e15c5..043a4863292ae 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -14,6 +14,8 @@ import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForSta import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; import replacePathInNestedState from './replacePathInNestedState'; +const RHP_SCREENS_OPENED_FROM_LHN = [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS]; + type Metainfo = { // Sometimes modal screens don't have information about what should be visible under the overlay. // That means such screen can have different screens under the overlay depending on what was already in the state. @@ -158,9 +160,9 @@ function getAdaptedState(state: PartialState if (topmostNestedRHPRoute) { let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute, policyID); - + const isRHPScreenOpenedFromLHN = topmostNestedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(topmostNestedRHPRoute?.name); // This may happen if this RHP doens't have a route that should be under the overlay defined. - if (!matchingRootRoute || (topmostNestedRHPRoute?.name && [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS].includes(topmostNestedRHPRoute?.name))) { + if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { metainfo.isCentralPaneAndBottomTabMandatory = false; metainfo.isFullScreenNavigatorMandatory = false; matchingRootRoute = matchingRootRoute ?? createCentralPaneNavigator({name: SCREENS.REPORT}); @@ -169,7 +171,9 @@ function getAdaptedState(state: PartialState // If the root route is type of FullScreenNavigator, the default bottom tab will be added. const matchingBottomTabRoute = getMatchingBottomTabRouteForState({routes: [matchingRootRoute]}); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); - routes.push(matchingRootRoute); + if (!isNarrowLayout || !isRHPScreenOpenedFromLHN) { + routes.push(matchingRootRoute); + } } routes.push(rhpNavigator); From bc368b96e328db1af9bce49c9b728ea9f339775d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 12:43:09 +0100 Subject: [PATCH 17/46] Fix displaying AvatarSkeleton --- src/components/AvatarSkeleton.tsx | 12 ++++++++---- src/components/AvatarWithIndicator.tsx | 5 ++++- src/styles/index.ts | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/AvatarSkeleton.tsx b/src/components/AvatarSkeleton.tsx index 0887830aa07ab..0b84043dcf54c 100644 --- a/src/components/AvatarSkeleton.tsx +++ b/src/components/AvatarSkeleton.tsx @@ -1,21 +1,25 @@ import React from 'react'; import {Circle} from 'react-native-svg'; import useTheme from '@hooks/useTheme'; +import variables from '@styles/variables'; import SkeletonViewContentLoader from './SkeletonViewContentLoader'; function AvatarSkeleton() { const theme = useTheme(); + + const skeletonCircleRadius = variables.componentSizeSmall / 2; + return ( ); diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index 4fde0be5bf246..42b91b3d2d719 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import useThemeStyles from '@hooks/useThemeStyles'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; import Avatar from './Avatar'; @@ -23,9 +24,11 @@ type AvatarWithIndicatorProps = { }; function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) { + const styles = useThemeStyles(); + return ( - + {isLoading ? ( ) : ( diff --git a/src/styles/index.ts b/src/styles/index.ts index 4b6460d25e825..96ba96c4ee6b3 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1408,8 +1408,8 @@ const styles = (theme: ThemeColors) => sidebarAvatar: { backgroundColor: theme.icon, borderRadius: 20, - height: variables.componentSizeNormal, - width: variables.componentSizeNormal, + height: variables.componentSizeSmall, + width: variables.componentSizeSmall, }, statusIndicator: (backgroundColor = theme.danger) => From 8b8059a623b9fd976ce1d1fbb29e64642e11adc1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 13:49:54 +0100 Subject: [PATCH 18/46] Handle dismissing RHP when FullScreenNavigator is opened --- src/libs/Navigation/linkTo.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 0eade256072d7..3c8a8ec7d7c1f 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -118,6 +118,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 28 Feb 2024 13:51:18 +0100 Subject: [PATCH 19/46] Fix linkTo --- src/libs/Navigation/linkTo.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 3c8a8ec7d7c1f..5e75772f52781 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -118,7 +118,6 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 28 Feb 2024 13:58:40 +0100 Subject: [PATCH 20/46] Dismiss RHP before creating a new workspace from the switcher --- src/libs/Navigation/linkTo.ts | 24 ++++++++++-------------- src/pages/WorkspaceSwitcherPage.tsx | 1 + 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 5e75772f52781..0eade256072d7 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -235,21 +235,17 @@ export default function linkTo(navigation: NavigationContainerRef { + Navigation.dismissModal(); App.createWorkspaceWithPolicyDraftAndNavigateToIt(); }} > From f6d954d27dc271a6a895bfe5cfb09bc59c73cb47 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 15:04:09 +0100 Subject: [PATCH 21/46] Refactor sidebarAvatar style --- src/styles/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index 96ba96c4ee6b3..300cc18b92a35 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1406,7 +1406,6 @@ const styles = (theme: ThemeColors) => }, sidebarAvatar: { - backgroundColor: theme.icon, borderRadius: 20, height: variables.componentSizeSmall, width: variables.componentSizeSmall, From 08a76455322cdf46307b8f1da17467518847224f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 16:39:08 +0100 Subject: [PATCH 22/46] Adjust getAdaptedState to the new FullScreenNavigator --- .../linkingConfig/getAdaptedStateFromPath.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index f04b0b38f2698..65211a30bd01c 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -229,14 +229,18 @@ function getAdaptedState(state: PartialState routes.push( createBottomTabNavigator( { - name: SCREENS.HOME, + name: SCREENS.SETTINGS.ROOT, }, policyID, ), ); - if (!isNarrowLayout) { - routes.push(createCentralPaneNavigator({name: SCREENS.REPORT})); - } + + routes.push( + createCentralPaneNavigator({ + name: SCREENS.SETTINGS.WORKSPACES, + }), + ); + routes.push(fullScreenNavigator); return { From 3e25a7d9a04ee213e992ef626eb3e7ba1fcba0c5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 17:12:59 +0100 Subject: [PATCH 23/46] Refactor BottomTabBar and TopBar --- .../BottomTabBar.tsx | 4 +-- .../createCustomBottomTabNavigator/TopBar.tsx | 34 +++++++++++-------- ...thOptionalStatus.js => BottomTabAvatar.js} | 15 +++----- src/pages/settings/InitialSettingsPage.tsx | 8 ++--- 4 files changed, 30 insertions(+), 31 deletions(-) rename src/pages/home/sidebar/{SignInOrAvatarWithOptionalStatus.js => BottomTabAvatar.js} (70%) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 6752bb9011066..abe648879486d 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -14,9 +14,9 @@ import useThemeStyles from '@hooks/useThemeStyles'; import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; -import {checkIfWorkspaceSettingsTabHasRBR, getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; +import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; -import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/SignInOrAvatarWithOptionalStatus'; +import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/BottomTabAvatar'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index d97556cf3c1d4..e78ca5f552ce9 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import SignInButton from '@pages/home/sidebar/SignInButton'; import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -35,10 +36,10 @@ function TopBar({policy}: TopBarProps) { return ( - + @@ -55,19 +56,22 @@ function TopBar({policy}: TopBarProps) { /> - - - Navigation.navigate(ROUTES.SEARCH))} - > - - - + {Session.isAnonymousUser() ? ( + + ) : ( + + Navigation.navigate(ROUTES.SEARCH))} + > + + + + )} ); diff --git a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js b/src/pages/home/sidebar/BottomTabAvatar.js similarity index 70% rename from src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js rename to src/pages/home/sidebar/BottomTabAvatar.js index 17d732a8080fa..4047235f93553 100644 --- a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/BottomTabAvatar.js @@ -3,10 +3,8 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React from 'react'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import * as Session from '@userActions/Session'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import PressableAvatarWithIndicator from './PressableAvatarWithIndicator'; -import SignInButton from './SignInButton'; const propTypes = { /** Whether the create menu is open or not */ @@ -20,13 +18,10 @@ const defaultProps = { isSelected: false, }; -function SignInOrAvatarWithOptionalStatus({isCreateMenuOpen, isSelected}) { +function BottomTabAvatar({isCreateMenuOpen, isSelected}) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = lodashGet(currentUserPersonalDetails, 'status.emojiCode', ''); - if (Session.isAnonymousUser()) { - return ; - } if (emojiStatus) { return ( ({ sectionStyle: { ...styles.pt4, @@ -177,7 +177,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa sectionTranslationKey: 'initialSettingsPage.workspaces', items: [ { - translationKey: 'common.workspaces', + translationKey: 'initialSettingsPage.workspaces', icon: Expensicons.Building, routeName: ROUTES.SETTINGS_WORKSPACES, brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(policies, policyMembers) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, @@ -215,7 +215,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa * Retuns a list of menu items data for general section * @returns object with translationKey, style and items for the general section */ - const generalMenuItemsData = useMemo(() => { + const generalMenuItemsData: Menu = useMemo(() => { const defaultMenu: Menu = { sectionStyle: { ...styles.pt4, From f914b527eb16f49ff05c869e7ca5c3b236cd27fc Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 18:41:51 +0100 Subject: [PATCH 24/46] Adjust types to ideal nav v2 --- src/components/HeaderWithBackButton/types.ts | 3 +- src/components/Indicator.tsx | 1 + src/languages/en.ts | 1 - .../linkingConfig/customGetPathFromState.ts | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 6 +- src/libs/Navigation/switchPolicyID.ts | 13 +--- src/libs/Navigation/types.ts | 1 + src/pages/WorkspaceSwitcherPage.tsx | 4 +- src/pages/home/sidebar/SidebarLinks.js | 13 +--- src/pages/settings/InitialSettingsPage.tsx | 78 +++++++++---------- src/pages/workspace/WorkspaceInitialPage.tsx | 5 +- src/pages/workspace/WorkspaceMembersPage.tsx | 4 +- .../workspace/bills/WorkspaceBillsPage.tsx | 4 +- .../workspace/card/WorkspaceCardPage.tsx | 4 +- .../categories/WorkspaceCategoriesPage.tsx | 6 +- .../invoices/WorkspaceInvoicesPage.tsx | 4 +- .../workspace/travel/WorkspaceTravelPage.tsx | 4 +- src/pages/workspace/withPolicy.tsx | 8 +- .../workflows/WorkspaceWorkflowsPage.tsx | 8 +- 19 files changed, 75 insertions(+), 94 deletions(-) diff --git a/src/components/HeaderWithBackButton/types.ts b/src/components/HeaderWithBackButton/types.ts index a789fe9e6d0a4..11724123282f8 100644 --- a/src/components/HeaderWithBackButton/types.ts +++ b/src/components/HeaderWithBackButton/types.ts @@ -1,11 +1,10 @@ import type {ReactNode} from 'react'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {Action} from '@hooks/useSingleExecution'; -import type {AvatarSource} from '@libs/UserUtils'; import type {StepCounterParams} from '@src/languages/types'; import type {AnchorPosition} from '@src/styles'; import type {PersonalDetails, Policy, Report} from '@src/types/onyx'; -import {Icon} from '@src/types/onyx/OnyxCommon'; +import type {Icon} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import type IconAsset from '@src/types/utils/IconAsset'; diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx index 486189c66710d..15a054429ca11 100644 --- a/src/components/Indicator.tsx +++ b/src/components/Indicator.tsx @@ -86,6 +86,7 @@ export default withOnyx({ bankAccountList: { key: ONYXKEYS.BANK_ACCOUNT_LIST, }, + // @ts-expect-error: ONYXKEYS.REIMBURSEMENT_ACCOUNT is conflicting with ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM reimbursementAccount: { key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, }, diff --git a/src/languages/en.ts b/src/languages/en.ts index fa49525280824..cf8823f5b2be0 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -875,7 +875,6 @@ export default { accountSettings: 'Account Settings', account: 'Account', general: 'General', - workspaces: 'Workspaces', }, closeAccountPage: { closeAccount: 'Close account', diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 2c2140e49f7aa..39d8c6c8ec1a6 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -8,7 +8,7 @@ import SCREENS from '@src/SCREENS'; const removePolicyIDParamFromState = (state: State) => { const stateCopy = _.cloneDeep(state); const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); - if (bottomTabRoute?.name && [SCREENS.HOME, SCREENS.SETTINGS.ROOT].includes(bottomTabRoute?.name) && bottomTabRoute?.params && 'policyID' in bottomTabRoute?.params) { + if (bottomTabRoute?.name && [SCREENS.HOME, SCREENS.SETTINGS.ROOT].includes(bottomTabRoute.name) && bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { delete bottomTabRoute.params.policyID; } return stateCopy; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 65211a30bd01c..40d77bca1abd1 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -14,7 +14,9 @@ import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForSta import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; import replacePathInNestedState from './replacePathInNestedState'; -const RHP_SCREENS_OPENED_FROM_LHN = [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS]; +const RHP_SCREENS_OPENED_FROM_LHN = [SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS] as const; + +type RHPScreenOpenedFromLHN = (typeof RHP_SCREENS_OPENED_FROM_LHN)[number]; type Metainfo = { // Sometimes modal screens don't have information about what should be visible under the overlay. @@ -162,7 +164,7 @@ function getAdaptedState(state: PartialState if (topmostNestedRHPRoute) { let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute, policyID); - const isRHPScreenOpenedFromLHN = topmostNestedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(topmostNestedRHPRoute?.name); + const isRHPScreenOpenedFromLHN = topmostNestedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(topmostNestedRHPRoute?.name as RHPScreenOpenedFromLHN); // This may happen if this RHP doens't have a route that should be under the overlay defined. if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { metainfo.isCentralPaneAndBottomTabMandatory = false; diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 69628e5db0a26..685c21d88e79a 100644 --- a/src/libs/Navigation/switchPolicyID.ts +++ b/src/libs/Navigation/switchPolicyID.ts @@ -61,7 +61,7 @@ function getActionForBottomTabNavigator(action: StackNavigationAction, state: Na }; } -export default function switchPolicyID(navigation: NavigationContainerRef | null, {policyID, route, isPolicyAdmin = false}: SwitchPolicyIDParams) { +export default function switchPolicyID(navigation: NavigationContainerRef | null, {policyID, route}: SwitchPolicyIDParams) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -121,23 +121,12 @@ export default function switchPolicyID(navigation: NavigationContainerRef { @@ -152,9 +149,5 @@ function SidebarLinks({onLinkClick, insets, optionListItems, isLoading, priority SidebarLinks.propTypes = propTypes; SidebarLinks.displayName = 'SidebarLinks'; -export default withOnyx({ - activePolicy: { - key: ({activeWorkspaceID}) => `${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID}`, - }, -})(SidebarLinks); +export default SidebarLinks; export {basePropTypes}; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index ac70c98654599..a3f78ebabc407 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -169,47 +169,47 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa }; }, [loginList, fundList, styles.accountSettingsSectionContainer, bankAccountList, userWallet?.errors, walletTerms?.errors]); - const workspaceMenuItemsData: Menu = useMemo( - () => ({ - sectionStyle: { - ...styles.pt4, + const workspaceMenuItemsData: Menu = useMemo(() => { + const items: MenuData[] = [ + { + translationKey: 'common.workspaces', + icon: Expensicons.Building, + routeName: ROUTES.SETTINGS_WORKSPACES, + brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(policies, policyMembers) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, }, - sectionTranslationKey: 'initialSettingsPage.workspaces', - items: [ - { - translationKey: 'initialSettingsPage.workspaces', - icon: Expensicons.Building, - routeName: ROUTES.SETTINGS_WORKSPACES, - brickRoadIndicator: hasGlobalWorkspaceSettingsRBR(policies, policyMembers) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + { + translationKey: 'allSettingsScreen.cardsAndDomains', + icon: Expensicons.CardsAndDomains, + action: () => { + Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL); }, - ...(shouldShowSubscriptionsMenu - ? [ - { - translationKey: 'allSettingsScreen.subscriptions', - icon: Expensicons.MoneyBag, - action: () => { - Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL); - }, - shouldShowRightIcon: true, - iconRight: Expensicons.NewWindow, - link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL), - }, - ] - : []), - { - translationKey: 'allSettingsScreen.cardsAndDomains', - icon: Expensicons.CardsAndDomains, - action: () => { - Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL); - }, - shouldShowRightIcon: true, - iconRight: Expensicons.NewWindow, - link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL), + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_DOMAINS_URL), + }, + ]; + + if (shouldShowSubscriptionsMenu) { + items.splice(1, 0, { + translationKey: 'allSettingsScreen.subscriptions', + icon: Expensicons.MoneyBag, + action: () => { + Link.openOldDotLink(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL); }, - ], - }), - [policies, policyMembers, styles.pt4], - ); + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.ADMIN_POLICIES_URL), + }); + } + + return { + sectionStyle: { + ...styles.pt4, + }, + sectionTranslationKey: 'common.workspaces', + items, + }; + }, [policies, policyMembers, styles.pt4]); /** * Retuns a list of menu items data for general section @@ -271,7 +271,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa ...defaultMenu.items, ].filter((item) => item.translationKey !== 'initialSettingsPage.signOut' && item.translationKey !== 'exitSurvey.goToExpensifyClassic'); - return {sectionStyle: styles.accountSettingsSectionContainer, sectionTranslationKey: 'initialSettingsPage.account', items: hybridAppMenuItems}; + return {sectionStyle: styles.accountSettingsSectionContainer, sectionTranslationKey: 'initialSettingsPage.general', items: hybridAppMenuItems}; } return defaultMenu; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 3fd1b77002f4f..106d64836c136 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -2,18 +2,16 @@ import {useNavigationState} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ScrollView, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import Breadcrumbs from '@components/Breadcrumbs'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; -import useActiveRoute from '@hooks/useActiveRoute'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useSingleExecution from '@hooks/useSingleExecution'; @@ -220,7 +218,6 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r subtitleKey={isEmptyObject(policy) ? undefined : 'workspace.common.notAuthorized'} > ; + StackScreenProps; /** * Inverts an object, equivalent of _.invert diff --git a/src/pages/workspace/bills/WorkspaceBillsPage.tsx b/src/pages/workspace/bills/WorkspaceBillsPage.tsx index 85cceb29b661a..e2dbe398b49fe 100644 --- a/src/pages/workspace/bills/WorkspaceBillsPage.tsx +++ b/src/pages/workspace/bills/WorkspaceBillsPage.tsx @@ -4,14 +4,14 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; import WorkspaceBillsNoVBAView from './WorkspaceBillsNoVBAView'; import WorkspaceBillsVBAView from './WorkspaceBillsVBAView'; -type WorkspaceBillsPageProps = StackScreenProps; +type WorkspaceBillsPageProps = StackScreenProps; function WorkspaceBillsPage({route}: WorkspaceBillsPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/card/WorkspaceCardPage.tsx b/src/pages/workspace/card/WorkspaceCardPage.tsx index 710ef37350267..079c715bffd6f 100644 --- a/src/pages/workspace/card/WorkspaceCardPage.tsx +++ b/src/pages/workspace/card/WorkspaceCardPage.tsx @@ -4,7 +4,7 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import type {CentralPaneNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@libs/Navigation/types'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; @@ -12,7 +12,7 @@ import WorkspaceCardNoVBAView from './WorkspaceCardNoVBAView'; import WorkspaceCardVBANoECardView from './WorkspaceCardVBANoECardView'; import WorkspaceCardVBAWithECardView from './WorkspaceCardVBAWithECardView'; -type WorkspaceCardPageProps = StackScreenProps; +type WorkspaceCardPageProps = StackScreenProps; function WorkspaceCardPage({route}: WorkspaceCardPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 7cd9972a6f576..9bbf7aae8162a 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -1,8 +1,8 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useMemo, useState} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; @@ -18,7 +18,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; -import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -39,7 +39,7 @@ type WorkspaceCategoriesOnyxProps = { policyCategories: OnyxEntry; }; -type WorkspaceCategoriesPageProps = WorkspaceCategoriesOnyxProps & StackScreenProps; +type WorkspaceCategoriesPageProps = WorkspaceCategoriesOnyxProps & StackScreenProps; function WorkspaceCategoriesPage({policyCategories, route}: WorkspaceCategoriesPageProps) { const {isSmallScreenWidth} = useWindowDimensions(); diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx index 96aa350496b5d..a00c4959cedb2 100644 --- a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx +++ b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx @@ -4,14 +4,14 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; import WorkspaceInvoicesNoVBAView from './WorkspaceInvoicesNoVBAView'; import WorkspaceInvoicesVBAView from './WorkspaceInvoicesVBAView'; -type WorkspaceInvoicesPageProps = StackScreenProps; +type WorkspaceInvoicesPageProps = StackScreenProps; function WorkspaceInvoicesPage({route}: WorkspaceInvoicesPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/travel/WorkspaceTravelPage.tsx b/src/pages/workspace/travel/WorkspaceTravelPage.tsx index 88dfe5254fcf8..c03bcc7cfb9be 100644 --- a/src/pages/workspace/travel/WorkspaceTravelPage.tsx +++ b/src/pages/workspace/travel/WorkspaceTravelPage.tsx @@ -4,14 +4,14 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import type {CentralPaneNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@libs/Navigation/types'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; import WorkspaceTravelNoVBAView from './WorkspaceTravelNoVBAView'; import WorkspaceTravelVBAView from './WorkspaceTravelVBAView'; -type WorkspaceTravelPageProps = StackScreenProps; +type WorkspaceTravelPageProps = StackScreenProps; function WorkspaceTravelPage({route}: WorkspaceTravelPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 76126040652b8..16af069fa0a2b 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -8,7 +8,7 @@ import {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import taxPropTypes from '@components/taxPropTypes'; import {translatableTextPropTypes} from '@libs/Localize'; -import type {BottomTabNavigatorParamList, CentralPaneNavigatorParamList, SettingsNavigatorParamList} from '@navigation/types'; +import type {CentralPaneNavigatorParamList, FullScreenNavigatorParamList, SettingsNavigatorParamList, WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; import policyMemberPropType from '@pages/policyMemberPropType'; import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; @@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; -type WorkspaceParamList = BottomTabNavigatorParamList & CentralPaneNavigatorParamList & SettingsNavigatorParamList; +type WorkspaceParamList = WorkspacesCentralPaneNavigatorParamList & FullScreenNavigatorParamList & CentralPaneNavigatorParamList & SettingsNavigatorParamList; type PolicyRoute = RouteProp>; function getPolicyIDFromRoute(route: PolicyRoute): string { @@ -148,5 +148,5 @@ export default function (WrappedComponent: })(forwardRef(WithPolicy)); } -export {policyPropTypes, policyDefaultProps}; -export type {WithPolicyOnyxProps, WithPolicyProps, PolicyRoute}; +export {policyDefaultProps, policyPropTypes}; +export type {PolicyRoute, WithPolicyOnyxProps, WithPolicyProps}; diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index fc1ed1d195604..9066f263adf0a 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -13,17 +13,17 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import type {CentralPaneNavigatorParamList} from '@navigation/types'; -import withPolicy from '@pages/workspace/withPolicy'; +import type {WorkspacesCentralPaneNavigatorParamList} from '@navigation/types'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import withPolicy from '@pages/workspace/withPolicy'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; -import ToggleSettingOptionRow from './ToggleSettingsOptionRow'; import type {ToggleSettingOptionRowProps} from './ToggleSettingsOptionRow'; +import ToggleSettingOptionRow from './ToggleSettingsOptionRow'; -type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; +type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const {translate} = useLocalize(); From a12814f4d7ac96f1611ddab6eb5aeac9e0ef0919 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 28 Feb 2024 18:47:54 +0100 Subject: [PATCH 25/46] Run prettier --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index abe648879486d..62c4b27693bbf 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -15,8 +15,8 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute' import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; -import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/BottomTabAvatar'; +import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; From e7227febb5ef8b46b4461c2c8ad2df2a589025cb Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 29 Feb 2024 13:13:37 +0100 Subject: [PATCH 26/46] Add fixes to ideal-nav-v2 --- src/components/Breadcrumbs.tsx | 7 ++++--- src/components/HeaderWithBackButton/index.tsx | 4 ++-- src/components/HeaderWithBackButton/types.ts | 5 +++-- src/components/MoneyReportHeader.tsx | 2 +- src/components/MoneyRequestHeader.tsx | 2 +- .../Navigators/BottomTabNavigator.tsx | 1 - .../BaseCentralPaneNavigator.tsx | 2 +- .../BottomTabBar.tsx | 4 ++-- .../createCustomBottomTabNavigator/TopBar.tsx | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 17 ++++++++++++----- src/libs/Navigation/types.ts | 8 -------- .../sidebar/PressableAvatarWithIndicator.js | 7 ++----- src/pages/settings/InitialSettingsPage.tsx | 15 ++++----------- src/styles/index.ts | 12 ++++++++++++ 14 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index def2ea494ed9a..d88508e57029b 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -31,10 +31,11 @@ type BreadcrumbsProps = { /** Styles to apply to the container */ style?: StyleProp; - secondaryBreadcrumbStyle?: StyleProp; + /** Styles to apply to the secondary breadcrumb text */ + secondaryBreadcrumbTextStyle?: StyleProp; }; -function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbStyle}: BreadcrumbsProps) { +function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbTextStyle}: BreadcrumbsProps) { const theme = useTheme(); const styles = useThemeStyles(); const [primaryBreadcrumb, secondaryBreadcrumb] = breadcrumbs; @@ -70,7 +71,7 @@ function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbStyle}: Breadcrumbs / {secondaryBreadcrumb.text} diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 0e2a5aeaf0865..acbff61baf40c 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -34,7 +34,7 @@ function HeaderWithBackButton({ report = null, policy, policyAvatar, - shouldShowAvatarWithDisplay = false, + shouldShowReportAvatarWithDisplay = false, shouldShowBackButton = true, shouldShowBorderBottom = false, shouldShowCloseButton = false, @@ -128,7 +128,7 @@ function HeaderWithBackButton({ type={policyAvatar?.type} /> )} - {shouldShowAvatarWithDisplay ? ( + {shouldShowReportAvatarWithDisplay ? ( & { /** Data to display a step counter in the header */ stepCounter?: StepCounterParams; - /** Whether we should show an avatar */ - shouldShowAvatarWithDisplay?: boolean; + /** Whether we should show a report avatar */ + shouldShowReportAvatarWithDisplay?: boolean; /** Parent report, if provided it will override props.report for AvatarWithDisplay */ parentReport?: OnyxEntry; @@ -123,6 +123,7 @@ type HeaderWithBackButtonProps = Partial & { /** Whether we should overlay the 3 dots menu */ shouldOverlayDots?: boolean; + /** Policy avatar to display in the header */ policyAvatar?: Icon; }; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 3f551da788f5e..cb3f538f5c7cb 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -116,7 +116,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money return ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index 9146eedad1ab8..16f403342a582 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -20,7 +20,7 @@ const settingsScreens = { [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, [SCREENS.SETTINGS.ABOUT]: () => require('../../../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, -}; +} satisfies Screens; function BaseCentralPaneNavigator() { const styles = useThemeStyles(); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 62c4b27693bbf..a5de82805ace0 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -15,7 +15,7 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute' import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; -import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/BottomTabAvatar'; +import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; @@ -93,7 +93,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - + ); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index e78ca5f552ce9..0dafb58e2c9bc 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -44,7 +44,7 @@ function TopBar({policy}: TopBarProps) { , policyID?: string): NavigationPartialRoute { +function createFullScreenNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { const routes = []; - routes.push({name: SCREENS.WORKSPACE.INITIAL, params: {policyID}}); + const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; + + // Both routes in FullScreenNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in FullScreenNavigator + routes.push({ + name: SCREENS.WORKSPACE.INITIAL, + params: { + policyID, + }, + }); if (route) { routes.push({ name: SCREENS.WORKSPACES_CENTRAL_PANE, @@ -93,7 +101,6 @@ function createFullScreenNavigator(route?: NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { @@ -132,7 +139,7 @@ function getMatchingRootRouteForRHPRoute( // Check for FullScreenNavigator for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { if (RHPNames && RHPNames.includes(route.name)) { - return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}, policyID); + return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: route.params}); } } } @@ -163,7 +170,7 @@ function getAdaptedState(state: PartialState const routes = []; if (topmostNestedRHPRoute) { - let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute, policyID); + let matchingRootRoute = getMatchingRootRouteForRHPRoute(topmostNestedRHPRoute); const isRHPScreenOpenedFromLHN = topmostNestedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(topmostNestedRHPRoute?.name as RHPScreenOpenedFromLHN); // This may happen if this RHP doens't have a route that should be under the overlay defined. if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4422bbbd1831a..02eb61b35d518 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -455,14 +455,6 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams; }; -// type SettingsCentralPaneNavigatorParamList = { -// [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; -// [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; -// [SCREENS.SETTINGS.SECURITY]: undefined; -// [SCREENS.SETTINGS.WALLET.ROOT]: undefined; -// [SCREENS.SETTINGS.ABOUT]: undefined; -// }; - type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.PROFILE]: { policyID: string; diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index 747b7fe8c1ca8..342d62a36cd31 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -9,7 +9,6 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; @@ -29,6 +28,7 @@ const propTypes = { /** Indicates whether the app is loading initial data */ isLoading: PropTypes.bool, + /** Whether the avatar is selected */ isSelected: PropTypes.bool, }; @@ -46,7 +46,6 @@ const defaultProps = { function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDetails, isLoading, isSelected}) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const theme = useTheme(); const showSettingsPage = useCallback(() => { if (isCreateMenuOpen) { @@ -57,8 +56,6 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta Navigation.navigate(ROUTES.SETTINGS); }, [isCreateMenuOpen]); - const buttonStyle = isSelected ? {borderWidth: 2, borderRadius: 30, borderColor: theme.splashBG} : {}; - return ( - + ; - // eslint-disable-next-line react/forbid-prop-types + /** Members of all the workspaces the user is member of */ policyMembers: OnyxCollection; }; @@ -203,13 +203,11 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa } return { - sectionStyle: { - ...styles.pt4, - }, + sectionStyle: styles.workspaceSettingsSectionContainer, sectionTranslationKey: 'common.workspaces', items, }; - }, [policies, policyMembers, styles.pt4]); + }, [policies, policyMembers, styles.workspaceSettingsSectionContainer]); /** * Retuns a list of menu items data for general section @@ -225,12 +223,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa { translationKey: 'exitSurvey.goToExpensifyClassic', icon: Expensicons.ExpensifyLogoNew, - action: () => { - Link.openOldDotLink(CONST.OLDDOT_URLS.INBOX); - }, - link: () => Link.buildOldDotURL(CONST.OLDDOT_URLS.INBOX), - iconRight: Expensicons.NewWindow, - shouldShowRightIcon: true, + routeName: ROUTES.SETTINGS_EXIT_SURVEY_REASON, }, { translationKey: 'initialSettingsPage.help', diff --git a/src/styles/index.ts b/src/styles/index.ts index a641fa88061ac..97c79004c116f 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1427,6 +1427,12 @@ const styles = (theme: ThemeColors) => width: variables.componentSizeSmall, }, + selectedAvatarBorder: { + borderWidth: 2, + borderRadius: 20, + borderColor: theme.success, + }, + statusIndicator: (backgroundColor = theme.danger) => ({ borderColor: theme.sidebar, @@ -2629,6 +2635,12 @@ const styles = (theme: ThemeColors) => ...spacing.pt0, }, + workspaceSettingsSectionContainer: { + borderBottomWidth: 1, + borderBottomColor: theme.border, + ...spacing.pt4, + }, + centralPaneAnimation: { height: CONST.CENTRAL_PANE_ANIMATION_HEIGHT, }, From 2931b4406116b3c01a69a4779211c366258c58fe Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 29 Feb 2024 14:11:36 +0100 Subject: [PATCH 27/46] Add docs to isSelected prop in AvatarWithOptionalStatus --- src/pages/home/sidebar/AvatarWithOptionalStatus.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js index ed6ddaa7c0203..dff977f1e74c1 100644 --- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js @@ -19,6 +19,7 @@ const propTypes = { /** Emoji status */ emojiStatus: PropTypes.string, + /** Whether the avatar is selected */ isSelected: PropTypes.bool, }; From 076efd49b2a2961d7983b623b1855330c86c65d0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 29 Feb 2024 14:59:28 +0100 Subject: [PATCH 28/46] Add fixes to ideal-nav-v2 --- src/components/Indicator.tsx | 2 +- src/pages/settings/InitialSettingsPage.tsx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Indicator.tsx b/src/components/Indicator.tsx index 15a054429ca11..e3d226a179998 100644 --- a/src/components/Indicator.tsx +++ b/src/components/Indicator.tsx @@ -46,7 +46,7 @@ function Indicator({reimbursementAccount, allPolicyMembers, policies, bankAccoun // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and // those should be cleaned out before doing any error checking - const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => !!policy)); + const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => policy?.id)); const cleanAllPolicyMembers = Object.fromEntries(Object.entries(allPolicyMembers ?? {}).filter(([, policyMembers]) => !!policyMembers)); // All of the error & info-checking methods are put into an array. This is so that using _.some() will return diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index b46b519d90473..c710a9c18dfcb 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -169,6 +169,10 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa }; }, [loginList, fundList, styles.accountSettingsSectionContainer, bankAccountList, userWallet?.errors, walletTerms?.errors]); + /** + * Retuns a list of menu items data for workspace section + * @returns object with translationKey, style and items for the workspace section + */ const workspaceMenuItemsData: Menu = useMemo(() => { const items: MenuData[] = [ { From 1dee0eab87823c00e227d8563bb3ccc674a65228 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 29 Feb 2024 17:23:52 +0100 Subject: [PATCH 29/46] Add fix for opening deeplinks to the FullScreenNavigator screens --- .../CustomFullScreenRouter.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index 04967db27c201..6f2c25631a716 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -10,7 +10,11 @@ const isAtLeastOneInState = (state: StackState, screenName: string): boolean => function adaptStateIfNecessary(state: StackState) { const isNarrowLayout = getIsNarrowLayout(); - const topmostWorkspaceCentralPaneRoute = state.routes.at(-1)?.state?.routes[0]; + const workspaceCentralPane = state.routes.at(-1); + const topmostWorkspaceCentralPaneRoute = workspaceCentralPane?.state?.routes[0]; + // When a screen from the FullScreenNavigator is opened from the deeplink then params should be passed to SCREENS.WORKSPACE.INITIAL from the variable defined below. + const workspacesCentralPaneParams = + workspaceCentralPane?.params && 'params' in workspaceCentralPane.params ? (workspaceCentralPane.params.params as Record) : undefined; // There should always be SETTINGS.ROOT screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) { @@ -23,7 +27,7 @@ function adaptStateIfNecessary(state: StackState) { // Unshift the root screen to fill left pane. state.routes.unshift({ name: SCREENS.WORKSPACE.INITIAL, - params: topmostWorkspaceCentralPaneRoute?.params, + params: topmostWorkspaceCentralPaneRoute?.params ?? workspacesCentralPaneParams, }); } } From 62ed5db6bcf444a7145a737e49bb41b79cba791d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 1 Mar 2024 15:52:44 +0100 Subject: [PATCH 30/46] Refactor createCustomFullScreenNavigator --- .../createCustomFullScreenNavigator/index.tsx | 36 ++----------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx index 61eaa7af3cc9b..f35c609402b0b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx @@ -2,34 +2,12 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React, {useEffect, useMemo} from 'react'; +import React, {useEffect} from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import navigationRef from '@libs/Navigation/navigationRef'; -import SCREENS from '@src/SCREENS'; import CustomFullScreenRouter from './CustomFullScreenRouter'; import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types'; -type Routes = StackNavigationState['routes']; -function reduceReportRoutes(routes: Routes): Routes { - const result: Routes = []; - let count = 0; - const reverseRoutes = [...routes].reverse(); - - reverseRoutes.forEach((route) => { - if (route.name === SCREENS.WORKSPACES_CENTRAL_PANE) { - // Remove all report routes except the last 3. This will improve performance. - if (count < 3) { - result.push(route); - count++; - } - } else { - result.push(route); - } - }); - - return result.reverse(); -} - function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, @@ -45,16 +23,6 @@ function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { const {isSmallScreenWidth} = useWindowDimensions(); - const stateToRender = useMemo(() => { - const result = reduceReportRoutes(state.routes); - - return { - ...state, - index: result.length - 1, - routes: [...result], - }; - }, [state]); - useEffect(() => { if (!navigationRef.isReady()) { return; @@ -69,7 +37,7 @@ function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { From 71a24255d6075d3d45b13980a994caab51f6a504 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 1 Mar 2024 17:43:22 +0100 Subject: [PATCH 31/46] Fix opening RHP in FullScreenNavigator --- .../Navigation/linkingConfig/getAdaptedStateFromPath.ts | 5 +++++ .../linkingConfig/getMatchingBottomTabRouteForState.ts | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 3ff52bcee2c79..e4a8464d7ddd8 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -182,6 +182,11 @@ function getAdaptedState(state: PartialState // If the root route is type of FullScreenNavigator, the default bottom tab will be added. const matchingBottomTabRoute = getMatchingBottomTabRouteForState({routes: [matchingRootRoute]}); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); + // When we open a screen in RHP from FullScreenNavigator, we need to add the appropriate screen in CentralPane. + // Then, when we close FullScreenNavigator, we will be redirected to the correct page in CentralPane. + if (matchingRootRoute.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { + routes.push(createCentralPaneNavigator({name: SCREENS.SETTINGS.WORKSPACES})); + } if (!isNarrowLayout || !isRHPScreenOpenedFromLHN) { routes.push(matchingRootRoute); } diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index e85e7ca950dd4..65d7f402ee569 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -1,5 +1,6 @@ import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; @@ -7,6 +8,12 @@ import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { const paramsWithPolicyID = policyID ? {policyID} : undefined; const defaultRoute = {name: SCREENS.HOME, params: paramsWithPolicyID}; + const isFullScreenNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + + if (isFullScreenNavigatorOpened) { + return {name: SCREENS.SETTINGS.ROOT, params: paramsWithPolicyID}; + } + const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state); if (topmostCentralPaneRoute === undefined) { From 53b488d8f0b988c1a6748f0ae9b83c343d82b4a8 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Mar 2024 17:38:45 +0100 Subject: [PATCH 32/46] Fix lint --- src/pages/home/sidebar/SidebarLinks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index 161d259d0b4f1..8c72575b7c018 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -40,7 +40,7 @@ const propTypes = { isActiveReport: PropTypes.func.isRequired, }; -function SidebarLinks({onLinkClick, insets, optionListItems, isLoading, priorityMode = CONST.PRIORITY_MODE.DEFAULT, isActiveReport, isCreateMenuOpen, activePolicy, reportIDsWithErrors}) { +function SidebarLinks({onLinkClick, insets, optionListItems, isLoading, priorityMode = CONST.PRIORITY_MODE.DEFAULT, isActiveReport, isCreateMenuOpen, reportIDsWithErrors}) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const modal = useRef({}); From c2e35981c538ad62ddef8872f29b526d6aa14e32 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 10:48:06 +0100 Subject: [PATCH 33/46] Add style fixes to ideal-nav-v2 --- src/pages/home/sidebar/PressableAvatarWithIndicator.js | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- src/styles/index.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index 342d62a36cd31..84b0e829300bc 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -63,7 +63,7 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta onPress={showSettingsPage} > - + - + dismissError(policyID)} diff --git a/src/styles/index.ts b/src/styles/index.ts index 5508eb7a4e1d4..ced0fe374023f 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1448,6 +1448,7 @@ const styles = (theme: ThemeColors) => }, selectedAvatarBorder: { + padding: 2, borderWidth: 2, borderRadius: 20, borderColor: theme.success, From 0f018bf9678cb7f1e32036aa9ebfe67bfad9dabe Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 10:56:58 +0100 Subject: [PATCH 34/46] Refactor bottomTabHeight --- src/styles/variables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 63611eccb1992..b907e7648320a 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -12,7 +12,7 @@ function getValueUsingPixelRatio(defaultValue: number, maxValue: number): number } export default { - bottomTabHeight: 80, + bottomTabHeight: 72, contentHeaderHeight: getValueUsingPixelRatio(72, 100), contentHeaderDesktopHeight: getValueUsingPixelRatio(80, 100), componentSizeSmall: getValueUsingPixelRatio(28, 32), From b4e232ae129849c0ff0c02f919b8edae2111fce9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 6 Mar 2024 14:10:41 +0100 Subject: [PATCH 35/46] Adjust HeaderWithBackButton size on workspace pages --- src/components/HeaderWithBackButton/index.tsx | 2 ++ src/components/HeaderWithBackButton/types.ts | 4 ++++ src/pages/workspace/WorkspaceInitialPage.tsx | 5 +++-- src/pages/workspace/WorkspacePageWithSections.tsx | 1 + src/pages/workspace/WorkspaceProfilePage.tsx | 2 +- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index d68c0be329237..21f3e9a3b6057 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -60,6 +60,7 @@ function HeaderWithBackButton({ shouldOverlay = false, singleExecution = (func) => func, shouldNavigateToTopMostReport = false, + style, }: HeaderWithBackButtonProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -83,6 +84,7 @@ function HeaderWithBackButton({ shouldShowBorderBottom && styles.borderBottom, shouldShowBackButton && styles.pl2, shouldOverlay && StyleSheet.absoluteFillObject, + style, ]} > diff --git a/src/components/HeaderWithBackButton/types.ts b/src/components/HeaderWithBackButton/types.ts index dbc2acf4fa6d5..243b3c3986ad8 100644 --- a/src/components/HeaderWithBackButton/types.ts +++ b/src/components/HeaderWithBackButton/types.ts @@ -1,4 +1,5 @@ import type {ReactNode} from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {Action} from '@hooks/useSingleExecution'; import type {StepCounterParams} from '@src/languages/types'; @@ -125,6 +126,9 @@ type HeaderWithBackButtonProps = Partial & { /** Policy avatar to display in the header */ policyAvatar?: Icon; + + /** Additional styles to add to the component */ + style?: StyleProp; }; export type {ThreeDotsMenuItem}; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 265107d5be94d..927999041f50f 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -227,16 +227,17 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r title={policyName} onBackButtonPress={Navigation.dismissModal} policyAvatar={policyAvatar} + style={styles.headerBarDesktopHeight} /> - + dismissError(policyID)} errors={policy?.errors} errorRowStyles={[styles.ph5, styles.pv2]} > - + {/* Ideally we should use MenuList component for MenuItems with singleExecution/Navigation actions. In this case where user can click on workspace avatar or menu items, we need to have a check for `isExecuting`. So, we are directly mapping menuItems. diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 32b76ef46202c..a596085f62932 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -164,6 +164,7 @@ function WorkspacePageWithSections({ shouldShowBackButton={isSmallScreenWidth || shouldShowBackButton} onBackButtonPress={() => Navigation.goBack(backButtonRoute ?? ROUTES.WORKSPACE_INITIAL.getRoute(policyID))} icon={icon ?? undefined} + style={styles.headerBarDesktopHeight} /> {(isLoading || firstRender.current) && shouldShowLoading && isFocused ? ( diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 796f32c343f2e..71f2d74c23a0c 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -87,7 +87,7 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi > {(hasVBA?: boolean) => ( - +
Date: Wed, 6 Mar 2024 14:57:12 +0100 Subject: [PATCH 36/46] Fix smallEditIcon style --- src/styles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index 25d11984442a2..0e2240cb08dc6 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3104,7 +3104,7 @@ const styles = (theme: ThemeColors) => smallEditIcon: { alignItems: 'center', backgroundColor: theme.buttonDefaultBG, - borderColor: theme.cardBG, + borderColor: theme.appBG, borderRadius: 20, borderWidth: 3, color: theme.textReversed, From 70e884cfd4b051f6b2959c2c76f463b35396a4fa Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 7 Mar 2024 10:57:39 +0100 Subject: [PATCH 37/46] Rename workspace settings routes --- src/ROUTES.ts | 112 +++++++++--------- src/libs/Navigation/linkTo.ts | 4 +- .../linkingConfig/customGetPathFromState.ts | 5 +- 3 files changed, 62 insertions(+), 59 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index bc8af4df56860..748937c12a934 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -443,116 +443,116 @@ const ROUTES = { WORKSPACE_NEW: 'workspace/new', WORKSPACE_NEW_ROOM: 'workspace/new-room', WORKSPACE_INITIAL: { - route: 'workspace/:policyID', - getRoute: (policyID: string) => `workspace/${policyID}` as const, + route: 'settings/workspaces/:policyID', + getRoute: (policyID: string) => `settings/workspaces/${policyID}` as const, }, WORKSPACE_INVITE: { - route: 'workspace/:policyID/invite', - getRoute: (policyID: string) => `workspace/${policyID}/invite` as const, + route: 'settings/workspaces/:policyID/invite', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/invite` as const, }, WORKSPACE_INVITE_MESSAGE: { - route: 'workspace/:policyID/invite-message', - getRoute: (policyID: string) => `workspace/${policyID}/invite-message` as const, + route: 'settings/workspaces/:policyID/invite-message', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/invite-message` as const, }, WORKSPACE_PROFILE: { - route: 'workspace/:policyID/profile', - getRoute: (policyID: string) => `workspace/${policyID}/profile` as const, + route: 'settings/workspaces/:policyID/profile', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile` as const, }, WORKSPACE_PROFILE_CURRENCY: { - route: 'workspace/:policyID/profile/currency', - getRoute: (policyID: string) => `workspace/${policyID}/profile/currency` as const, + route: 'settings/workspaces/:policyID/profile/currency', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/currency` as const, }, WORKSPACE_PROFILE_NAME: { - route: 'workspace/:policyID/profile/name', - getRoute: (policyID: string) => `workspace/${policyID}/profile/name` as const, + route: 'settings/workspaces/:policyID/profile/name', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/name` as const, }, WORKSPACE_PROFILE_DESCRIPTION: { - route: 'workspace/:policyID/profile/description', - getRoute: (policyID: string) => `workspace/${policyID}/profile/description` as const, + route: 'settings/workspaces/:policyID/profile/description', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/description` as const, }, WORKSPACE_PROFILE_SHARE: { - route: 'workspace/:policyID/profile/share', - getRoute: (policyID: string) => `workspace/${policyID}/profile/share` as const, + route: 'settings/workspaces/:policyID/profile/share', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/profile/share` as const, }, WORKSPACE_AVATAR: { - route: 'workspace/:policyID/avatar', - getRoute: (policyID: string) => `workspace/${policyID}/avatar` as const, + route: 'settings/workspaces/:policyID/avatar', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/avatar` as const, }, WORKSPACE_SETTINGS_CURRENCY: { - route: 'workspace/:policyID/settings/currency', - getRoute: (policyID: string) => `workspace/${policyID}/settings/currency` as const, + route: 'settings/workspaces/:policyID/settings/currency', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/settings/currency` as const, }, WORKSPACE_WORKFLOWS: { - route: 'workspace/:policyID/workflows', - getRoute: (policyID: string) => `workspace/${policyID}/workflows` as const, + route: 'settings/workspaces/:policyID/workflows', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/workflows` as const, }, WORKSPACE_WORKFLOWS_APPROVER: { - route: 'workspace/:policyID/settings/workflows/approver', - getRoute: (policyId: string) => `workspace/${policyId}/settings/workflows/approver` as const, + route: 'settings/workspaces/:policyID/settings/workflows/approver', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/settings/workflows/approver` as const, }, WORKSPACE_WORKFLOWS_AUTOREPORTING_FREQUENCY: { - route: 'workspace/:policyID/settings/workflows/auto-reporting-frequency', - getRoute: (policyID: string) => `workspace/${policyID}/settings/workflows/auto-reporting-frequency` as const, + route: 'settings/workspaces/:policyID/settings/workflows/auto-reporting-frequency', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/settings/workflows/auto-reporting-frequency` as const, }, WORKSPACE_WORKFLOWS_AUTOREPORTING_MONTHLY_OFFSET: { - route: 'workspace/:policyID/settings/workflows/auto-reporting-frequency/monthly-offset', - getRoute: (policyID: string) => `workspace/${policyID}/settings/workflows/auto-reporting-frequency/monthly-offset` as const, + route: 'settings/workspaces/:policyID/settings/workflows/auto-reporting-frequency/monthly-offset', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/settings/workflows/auto-reporting-frequency/monthly-offset` as const, }, WORKSPACE_CARD: { - route: 'workspace/:policyID/card', - getRoute: (policyID: string) => `workspace/${policyID}/card` as const, + route: 'settings/workspaces/:policyID/card', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/card` as const, }, WORKSPACE_REIMBURSE: { - route: 'workspace/:policyID/reimburse', - getRoute: (policyID: string) => `workspace/${policyID}/reimburse` as const, + route: 'settings/workspaces/:policyID/reimburse', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/reimburse` as const, }, WORKSPACE_RATE_AND_UNIT: { - route: 'workspace/:policyID/rateandunit', - getRoute: (policyID: string) => `workspace/${policyID}/rateandunit` as const, + route: 'settings/workspaces/:policyID/rateandunit', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/rateandunit` as const, }, WORKSPACE_RATE_AND_UNIT_RATE: { - route: 'workspace/:policyID/rateandunit/rate', - getRoute: (policyID: string) => `workspace/${policyID}/rateandunit/rate` as const, + route: 'settings/workspaces/:policyID/rateandunit/rate', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/rateandunit/rate` as const, }, WORKSPACE_RATE_AND_UNIT_UNIT: { - route: 'workspace/:policyID/rateandunit/unit', - getRoute: (policyID: string) => `workspace/${policyID}/rateandunit/unit` as const, + route: 'settings/workspaces/:policyID/rateandunit/unit', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/rateandunit/unit` as const, }, WORKSPACE_BILLS: { - route: 'workspace/:policyID/bills', - getRoute: (policyID: string) => `workspace/${policyID}/bills` as const, + route: 'settings/workspaces/:policyID/bills', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/bills` as const, }, WORKSPACE_INVOICES: { - route: 'workspace/:policyID/invoices', - getRoute: (policyID: string) => `workspace/${policyID}/invoices` as const, + route: 'settings/workspaces/:policyID/invoices', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/invoices` as const, }, WORKSPACE_TRAVEL: { - route: 'workspace/:policyID/travel', - getRoute: (policyID: string) => `workspace/${policyID}/travel` as const, + route: 'settings/workspaces/:policyID/travel', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/travel` as const, }, WORKSPACE_MEMBERS: { - route: 'workspace/:policyID/members', - getRoute: (policyID: string) => `workspace/${policyID}/members` as const, + route: 'settings/workspaces/:policyID/members', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/members` as const, }, WORKSPACE_CATEGORIES: { - route: 'workspace/:policyID/categories', - getRoute: (policyID: string) => `workspace/${policyID}/categories` as const, + route: 'settings/workspaces/:policyID/categories', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories` as const, }, WORKSPACE_CATEGORY_SETTINGS: { - route: 'workspace/:policyID/categories/:categoryName', - getRoute: (policyID: string, categoryName: string) => `workspace/${policyID}/categories/${encodeURI(categoryName)}` as const, + route: 'settings/workspaces/:policyID/categories/:categoryName', + getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURI(categoryName)}` as const, }, WORKSPACE_CATEGORIES_SETTINGS: { - route: 'workspace/:policyID/categories/settings', - getRoute: (policyID: string) => `workspace/${policyID}/categories/settings` as const, + route: 'settings/workspaces/:policyID/categories/settings', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories/settings` as const, }, WORKSPACE_CATEGORY_CREATE: { - route: 'workspace/:policyID/categories/new', - getRoute: (policyID: string) => `workspace/${policyID}/categories/new` as const, + route: 'settings/workspaces/:policyID/categories/new', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories/new` as const, }, WORKSPACE_TAGS: { - route: 'workspace/:policyID/tags', - getRoute: (policyID: string) => `workspace/${policyID}/tags` as const, + route: 'settings/workspaces/:policyID/tags', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/tags` as const, }, // Referral program promotion REFERRAL_DETAILS_MODAL: { diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 0eade256072d7..2a00895f0492e 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -135,7 +135,9 @@ export default function linkTo(navigation: NavigationContainerRef) => { const stateCopy = _.cloneDeep(state); const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); - if (bottomTabRoute?.name && [SCREENS.HOME, SCREENS.SETTINGS.ROOT].includes(bottomTabRoute.name) && bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { + if (bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { delete bottomTabRoute.params.policyID; } return stateCopy; @@ -19,7 +19,8 @@ const customGetPathFromState: typeof getPathFromState = (state, options) => { const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); const policyIDFromState = getPolicyIDFromState(state as State); - return `${policyIDFromState ? `/w/${policyIDFromState}` : ''}${path}`; + const isHomeOpened = getTopmostBottomTabRoute(state as State)?.name === SCREENS.HOME; + return `${policyIDFromState && isHomeOpened ? `/w/${policyIDFromState}` : ''}${path}`; }; export default customGetPathFromState; From 210cc16dfafdf7ca9e54111908df781e193d9c74 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 7 Mar 2024 12:28:32 +0100 Subject: [PATCH 38/46] Remove comments --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 9 +-------- .../linkingConfig/getMatchingBottomTabRouteForState.ts | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 59f11b652a049..95e3d1831138b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -42,14 +42,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps const navigationState = navigation.getState() as State | undefined; const routes = navigationState?.routes; const currentRoute = routes?.[navigationState?.index ?? 0]; - if ( - // When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method. - // To prevent this, the value of the bottomTabRoute?.name is checked here - // bottomTabRoute?.name === SCREENS.WORKSPACE.INITIAL || - currentRoute && - currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && - currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR - ) { + if (currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) { return; } diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index 65d7f402ee569..fd45685acf231 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -21,9 +21,6 @@ function getMatchingBottomTabRouteForState(state: State, pol } const tabName = CENTRAL_PANE_TO_TAB_MAPPING[topmostCentralPaneRoute.name]; - // if (tabName === SCREENS.WORKSPACE.INITIAL) { - // return {name: tabName, params: topmostCentralPaneRoute.params}; - // } return {name: tabName, params: paramsWithPolicyID}; } From 9549e6d23a081aaf17d8ec99f3dff69e50752314 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 7 Mar 2024 18:13:34 +0100 Subject: [PATCH 39/46] Add bottom tab style fixes --- src/components/FloatingActionButton.tsx | 20 +++++----- .../BottomTabBar.tsx | 25 +++++++------ .../home/sidebar/AvatarWithOptionalStatus.js | 37 +++++++------------ src/pages/home/sidebar/BottomTabAvatar.js | 15 +++++++- .../sidebar/PressableAvatarWithIndicator.js | 24 +++--------- 5 files changed, 56 insertions(+), 65 deletions(-) diff --git a/src/components/FloatingActionButton.tsx b/src/components/FloatingActionButton.tsx index 9b68916c4003d..2c4ca9c27d7b7 100644 --- a/src/components/FloatingActionButton.tsx +++ b/src/components/FloatingActionButton.tsx @@ -103,13 +103,13 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo }; return ( - - - + + + { fabPressable.current = el; @@ -135,9 +135,9 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo /> - - - + + + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 95e3d1831138b..92eebe9d08b17 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -60,16 +60,16 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps return ( - - { - Navigation.navigate(ROUTES.HOME); - }} - role={CONST.ROLE.BUTTON} - accessibilityLabel={translate('common.chats')} - wrapperStyle={styles.flex1} - style={styles.bottomTabBarItem} - > + { + Navigation.navigate(ROUTES.HOME); + }} + role={CONST.ROLE.BUTTON} + accessibilityLabel={translate('common.chats')} + wrapperStyle={styles.flex1} + style={styles.bottomTabBarItem} + > + )} - - + + + diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js index dff977f1e74c1..cedfb20b55d66 100644 --- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js @@ -1,15 +1,12 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import PropTypes from 'prop-types'; -import React, {useCallback} from 'react'; +import React from 'react'; import {View} from 'react-native'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import Text from '@components/Text'; -import Tooltip from '@components/Tooltip'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; import PressableAvatarWithIndicator from './PressableAvatarWithIndicator'; const propTypes = { @@ -21,48 +18,40 @@ const propTypes = { /** Whether the avatar is selected */ isSelected: PropTypes.bool, + + onPress: PropTypes.func, }; const defaultProps = { isCreateMenuOpen: false, emojiStatus: '', isSelected: false, + onPress: () => {}, }; -function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen, isSelected}) { +function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen, isSelected, onPress}) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const showStatusPage = useCallback(() => { - if (isCreateMenuOpen) { - // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon - return; - } - - Navigation.setShouldPopAllStateOnUP(); - Navigation.navigate(ROUTES.SETTINGS_STATUS); - }, [isCreateMenuOpen]); - return ( - - - {emojiStatus} - - + + {emojiStatus} + ); diff --git a/src/pages/home/sidebar/BottomTabAvatar.js b/src/pages/home/sidebar/BottomTabAvatar.js index 4047235f93553..f474612df1b62 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.js +++ b/src/pages/home/sidebar/BottomTabAvatar.js @@ -1,8 +1,10 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, {useCallback} from 'react'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import Navigation from '@libs/Navigation/Navigation'; +import ROUTES from '@src/ROUTES'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import PressableAvatarWithIndicator from './PressableAvatarWithIndicator'; @@ -22,12 +24,22 @@ function BottomTabAvatar({isCreateMenuOpen, isSelected}) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = lodashGet(currentUserPersonalDetails, 'status.emojiCode', ''); + const showSettingsPage = useCallback(() => { + if (isCreateMenuOpen) { + // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon + return; + } + + Navigation.navigate(ROUTES.SETTINGS); + }, [isCreateMenuOpen]); + if (emojiStatus) { return ( ); } @@ -35,6 +47,7 @@ function BottomTabAvatar({isCreateMenuOpen, isSelected}) { ); } diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index 84b0e829300bc..3e0f53fd3248d 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -1,7 +1,7 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useCallback} from 'react'; +import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import AvatarWithIndicator from '@components/AvatarWithIndicator'; @@ -11,17 +11,12 @@ import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalD import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; import * as UserUtils from '@libs/UserUtils'; import personalDetailsPropType from '@pages/personalDetailsPropType'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; const propTypes = { - /** Whether the create menu is open or not */ - isCreateMenuOpen: PropTypes.bool, - /** The personal details of the person who is logged in */ currentUserPersonalDetails: personalDetailsPropType, @@ -30,10 +25,11 @@ const propTypes = { /** Whether the avatar is selected */ isSelected: PropTypes.bool, + + onPress: PropTypes.func, }; const defaultProps = { - isCreateMenuOpen: false, currentUserPersonalDetails: { pendingFields: {avatar: ''}, accountID: '', @@ -41,26 +37,18 @@ const defaultProps = { }, isLoading: true, isSelected: false, + onPress: () => {}, }; -function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDetails, isLoading, isSelected}) { +function PressableAvatarWithIndicator({currentUserPersonalDetails, isLoading, isSelected, onPress}) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const showSettingsPage = useCallback(() => { - if (isCreateMenuOpen) { - // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon - return; - } - - Navigation.navigate(ROUTES.SETTINGS); - }, [isCreateMenuOpen]); - return ( From 858178c4e8f1caeb313dbe4b7f6a72b2c541f0c0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 11 Mar 2024 09:14:35 +0100 Subject: [PATCH 40/46] Refactor docs and migration of BottomTabAvatar to TS --- src/components/AvatarSkeleton.tsx | 1 - .../CustomFullScreenRouter.tsx | 7 +++--- .../home/sidebar/AvatarWithOptionalStatus.js | 8 ++----- ...BottomTabAvatar.js => BottomTabAvatar.tsx} | 22 +++++-------------- .../sidebar/PressableAvatarWithIndicator.js | 1 + 5 files changed, 13 insertions(+), 26 deletions(-) rename src/pages/home/sidebar/{BottomTabAvatar.js => BottomTabAvatar.tsx} (69%) diff --git a/src/components/AvatarSkeleton.tsx b/src/components/AvatarSkeleton.tsx index 0b84043dcf54c..a6781448c3ba1 100644 --- a/src/components/AvatarSkeleton.tsx +++ b/src/components/AvatarSkeleton.tsx @@ -6,7 +6,6 @@ import SkeletonViewContentLoader from './SkeletonViewContentLoader'; function AvatarSkeleton() { const theme = useTheme(); - const skeletonCircleRadius = variables.componentSizeSmall / 2; return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index 6f2c25631a716..eb19f891ecd5d 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -12,11 +12,12 @@ function adaptStateIfNecessary(state: StackState) { const isNarrowLayout = getIsNarrowLayout(); const workspaceCentralPane = state.routes.at(-1); const topmostWorkspaceCentralPaneRoute = workspaceCentralPane?.state?.routes[0]; + // When a screen from the FullScreenNavigator is opened from the deeplink then params should be passed to SCREENS.WORKSPACE.INITIAL from the variable defined below. const workspacesCentralPaneParams = workspaceCentralPane?.params && 'params' in workspaceCentralPane.params ? (workspaceCentralPane.params.params as Record) : undefined; - // There should always be SETTINGS.ROOT screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. + // There should always be WORKSPACE.INITIAL screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment @@ -33,8 +34,8 @@ function adaptStateIfNecessary(state: StackState) { } // If the screen is wide, there should be at least two screens inside: - // - SETINGS.ROOT to cover left pane. - // - SETTINGS_CENTRAL_PANE to cover central pane. + // - WORKSPACE.INITIAL to cover left pane. + // - WORKSPACES_CENTRAL_PANE to cover central pane. if (!isNarrowLayout) { if (!isAtLeastOneInState(state, SCREENS.WORKSPACES_CENTRAL_PANE)) { // @ts-expect-error Updating read only property diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js index cedfb20b55d66..942d5c1da1f28 100644 --- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js +++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js @@ -10,33 +10,29 @@ import CONST from '@src/CONST'; import PressableAvatarWithIndicator from './PressableAvatarWithIndicator'; const propTypes = { - /** Whether the create menu is open or not */ - isCreateMenuOpen: PropTypes.bool, - /** Emoji status */ emojiStatus: PropTypes.string, /** Whether the avatar is selected */ isSelected: PropTypes.bool, + /** Callback called when the avatar or status icon is pressed */ onPress: PropTypes.func, }; const defaultProps = { - isCreateMenuOpen: false, emojiStatus: '', isSelected: false, onPress: () => {}, }; -function AvatarWithOptionalStatus({emojiStatus, isCreateMenuOpen, isSelected, onPress}) { +function AvatarWithOptionalStatus({emojiStatus, isSelected, onPress}) { const styles = useThemeStyles(); const {translate} = useLocalize(); return ( diff --git a/src/pages/home/sidebar/BottomTabAvatar.js b/src/pages/home/sidebar/BottomTabAvatar.tsx similarity index 69% rename from src/pages/home/sidebar/BottomTabAvatar.js rename to src/pages/home/sidebar/BottomTabAvatar.tsx index f474612df1b62..cddcd49c90ec1 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.js +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -1,6 +1,4 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import Navigation from '@libs/Navigation/Navigation'; @@ -8,21 +6,17 @@ import ROUTES from '@src/ROUTES'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import PressableAvatarWithIndicator from './PressableAvatarWithIndicator'; -const propTypes = { +type BottomTabAvatarProps = { /** Whether the create menu is open or not */ - isCreateMenuOpen: PropTypes.bool, + isCreateMenuOpen?: boolean; - isSelected: PropTypes.bool, + /** Whether the avatar is selected */ + isSelected?: boolean; }; -const defaultProps = { - isCreateMenuOpen: false, - isSelected: false, -}; - -function BottomTabAvatar({isCreateMenuOpen, isSelected}) { +function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) { const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const emojiStatus = lodashGet(currentUserPersonalDetails, 'status.emojiCode', ''); + const emojiStatus = currentUserPersonalDetails?.status?.emojiCode ?? ''; const showSettingsPage = useCallback(() => { if (isCreateMenuOpen) { @@ -37,7 +31,6 @@ function BottomTabAvatar({isCreateMenuOpen, isSelected}) { return ( @@ -45,14 +38,11 @@ function BottomTabAvatar({isCreateMenuOpen, isSelected}) { } return ( ); } -BottomTabAvatar.propTypes = propTypes; -BottomTabAvatar.defaultProps = defaultProps; BottomTabAvatar.displayName = 'BottomTabAvatar'; export default BottomTabAvatar; diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index 3e0f53fd3248d..a7345ff6c14a4 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -26,6 +26,7 @@ const propTypes = { /** Whether the avatar is selected */ isSelected: PropTypes.bool, + /** Callback called when the avatar is pressed */ onPress: PropTypes.func, }; From f9f71d2bdba2be54aebeb5e6fbd62e87b973a3da Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 11 Mar 2024 12:18:48 +0100 Subject: [PATCH 41/46] Fix displaying breadcrumbs in the TopBar --- src/components/Breadcrumbs.tsx | 7 ++----- .../createCustomBottomTabNavigator/TopBar.tsx | 13 +++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index d88508e57029b..e8339f652ac8b 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -30,12 +30,9 @@ type BreadcrumbsProps = { /** Styles to apply to the container */ style?: StyleProp; - - /** Styles to apply to the secondary breadcrumb text */ - secondaryBreadcrumbTextStyle?: StyleProp; }; -function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbTextStyle}: BreadcrumbsProps) { +function Breadcrumbs({breadcrumbs, style}: BreadcrumbsProps) { const theme = useTheme(); const styles = useThemeStyles(); const [primaryBreadcrumb, secondaryBreadcrumb] = breadcrumbs; @@ -71,7 +68,7 @@ function Breadcrumbs({breadcrumbs, style, secondaryBreadcrumbTextStyle}: Breadcr / {secondaryBreadcrumb.text} diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index 0dafb58e2c9bc..38bfe4af9ab63 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -31,7 +31,11 @@ function TopBar({policy}: TopBarProps) { const theme = useTheme(); const {translate} = useLocalize(); - const title = policy?.name ?? translate('common.chats'); + const headerBreadcrumb = policy?.name + ? {type: CONST.BREADCRUMB_TYPE.STRONG, text: policy.name} + : { + type: CONST.BREADCRUMB_TYPE.ROOT, + }; return ( @@ -44,13 +48,10 @@ function TopBar({policy}: TopBarProps) { From a35d3c97742d0111524415e58d5e1178f31564b7 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 11 Mar 2024 12:30:36 +0100 Subject: [PATCH 42/46] Check is user anonymous before navigating to settings --- src/pages/home/sidebar/BottomTabAvatar.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index cddcd49c90ec1..15134b7621614 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -1,6 +1,7 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import React, {useCallback} from 'react'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import ROUTES from '@src/ROUTES'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; @@ -24,7 +25,7 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return; } - Navigation.navigate(ROUTES.SETTINGS); + interceptAnonymousUser(() => Navigation.navigate(ROUTES.SETTINGS)); }, [isCreateMenuOpen]); if (emojiStatus) { From 4d62f8f76d4aae8b3964e948f93e6298735e96ca Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 11 Mar 2024 16:54:50 +0100 Subject: [PATCH 43/46] Fix navigating back in WorkspacesPageWithSections --- src/pages/workspace/WorkspacePageWithSections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index a596085f62932..5dfe755a1f50e 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -162,7 +162,7 @@ function WorkspacePageWithSections({ title={headerText} guidesCallTaskID={guidesCallTaskID} shouldShowBackButton={isSmallScreenWidth || shouldShowBackButton} - onBackButtonPress={() => Navigation.goBack(backButtonRoute ?? ROUTES.WORKSPACE_INITIAL.getRoute(policyID))} + onBackButtonPress={() => Navigation.goBack(backButtonRoute)} icon={icon ?? undefined} style={styles.headerBarDesktopHeight} /> From a303d9fede0849a4399d6f89daa865b46bd90e9b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 11 Mar 2024 19:03:44 +0100 Subject: [PATCH 44/46] Add resetToHome method and prevent from creating workspaces by anonymous users --- src/components/Breadcrumbs.tsx | 2 +- src/libs/Navigation/Navigation.ts | 15 ++++++++++++++- src/libs/actions/Session/index.ts | 9 ++++----- src/pages/WorkspaceSwitcherPage.tsx | 3 ++- src/pages/workspace/WorkspacePageWithSections.tsx | 1 - src/pages/workspace/WorkspacesListPage.tsx | 7 ++++--- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx index e8339f652ac8b..34bc3f7e30c8e 100644 --- a/src/components/Breadcrumbs.tsx +++ b/src/components/Breadcrumbs.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; +import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import LogoComponent from '@assets/images/expensify-wordmark.svg'; import useTheme from '@hooks/useTheme'; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4cd6a141bd3ba..c55145a5d5809 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -19,7 +19,7 @@ import linkingConfig from './linkingConfig'; import linkTo from './linkTo'; import navigationRef from './navigationRef'; import switchPolicyID from './switchPolicyID'; -import type {State, StateOrRoute, SwitchPolicyIDParams} from './types'; +import type {NavigationStateRoute, State, StateOrRoute, SwitchPolicyIDParams} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -234,6 +234,18 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT navigationRef.current.goBack(); } +/** + * Reset the navigation state to Home page + */ +function resetToHome() { + const rootState = navigationRef.getRootState(); + const bottomTabKey = rootState.routes.find((item: NavigationStateRoute) => item.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR)?.state?.key; + if (bottomTabKey) { + navigationRef.dispatch({...StackActions.popToTop(), target: bottomTabKey}); + } + navigationRef.dispatch({...StackActions.popToTop(), target: rootState.key}); +} + /** * Close the full screen modal. */ @@ -366,6 +378,7 @@ export default { parseHybridAppUrl, closeFullScreen, navigateWithSwitchPolicyID, + resetToHome, }; export {navigationRef}; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 07bc7f3ed4187..3cd516344fa46 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -184,7 +184,7 @@ function hasStashedSession(): boolean { return Boolean(stashedSession.authToken && stashedCredentials.autoGeneratedLogin && stashedCredentials.autoGeneratedLogin !== ''); } -function signOutAndRedirectToSignIn(shouldReplaceCurrentScreen?: boolean, shouldStashSession?: boolean) { +function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSession?: boolean) { Log.info('Redirecting to Sign In because signOut() was called'); hideContextMenu(false); if (!isAnonymousUser()) { @@ -233,11 +233,10 @@ function signOutAndRedirectToSignIn(shouldReplaceCurrentScreen?: boolean, should if (Navigation.isActiveRoute(ROUTES.SIGN_IN_MODAL)) { return; } - if (shouldReplaceCurrentScreen) { - Navigation.navigate(ROUTES.SIGN_IN_MODAL, CONST.NAVIGATION.TYPE.UP); - } else { - Navigation.navigate(ROUTES.SIGN_IN_MODAL); + if (shouldResetToHome) { + Navigation.resetToHome(); } + Navigation.navigate(ROUTES.SIGN_IN_MODAL); Linking.getInitialURL().then((url) => { const reportID = ReportUtils.getReportIDFromLink(url); if (reportID) { diff --git a/src/pages/WorkspaceSwitcherPage.tsx b/src/pages/WorkspaceSwitcherPage.tsx index 121299b9335c3..2eb5ecaf373f8 100644 --- a/src/pages/WorkspaceSwitcherPage.tsx +++ b/src/pages/WorkspaceSwitcherPage.tsx @@ -18,6 +18,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -219,7 +220,7 @@ function WorkspaceSwitcherPage({policies}: WorkspaceSwitcherPageProps) { role={CONST.ROLE.BUTTON} onPress={() => { Navigation.goBack(); - App.createWorkspaceWithPolicyDraftAndNavigateToIt(); + interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()); }} > {({hovered}) => ( diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 5dfe755a1f50e..c7d467a05928d 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -19,7 +19,6 @@ import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimburs import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; -import ROUTES from '@src/ROUTES'; import type {Policy, ReimbursementAccount, User} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 948cd2fd83c4d..e1a7e1e94ca97 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -24,6 +24,7 @@ import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -355,7 +356,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r success medium text={translate('workspace.new.newWorkspace')} - onPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} + onPress={() => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt())} /> @@ -366,7 +367,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r subtitle={translate('workspace.emptyWorkspace.subtitle')} ctaText={translate('workspace.new.newWorkspace')} ctaAccessibilityLabel={translate('workspace.new.newWorkspace')} - onCtaPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} + onCtaPress={() => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt())} illustration={LottieAnimations.WorkspacePlanet} // We use this style to vertically center the illustration, as the original illustration is not centered illustrationStyle={styles.emptyWorkspaceIllustrationStyle} @@ -394,7 +395,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r success medium text={translate('workspace.new.newWorkspace')} - onPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} + onPress={() => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt())} /> Date: Tue, 12 Mar 2024 16:20:06 +0100 Subject: [PATCH 45/46] Increase borderRadius in sidebarAvatar style --- src/styles/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index 4bc8ef9f2219e..3cfb38ef4bab4 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1442,7 +1442,7 @@ const styles = (theme: ThemeColors) => }, sidebarAvatar: { - borderRadius: 20, + borderRadius: 28, height: variables.componentSizeSmall, width: variables.componentSizeSmall, }, From 8ac018aae6e84e3e5154bcfd60d0924a7bc69b65 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 12 Mar 2024 17:20:22 +0100 Subject: [PATCH 46/46] Fix navigating back from workspace settings pages --- src/pages/workspace/WorkspaceInitialPage.tsx | 4 ++-- src/pages/workspace/WorkspacePageWithSections.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index f4229d9cc69fa..633822cc26118 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -236,8 +236,8 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, policyMembers, r style={[styles.pb0]} > diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index c7d467a05928d..9acddc3439d19 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -151,8 +151,8 @@ function WorkspacePageWithSections({ shouldShowOfflineIndicatorInWideScreen={shouldShowOfflineIndicatorInWideScreen && !shouldShow} >