Skip to content

Commit

Permalink
Merge pull request #24 from software-mansion-labs/@kosmydel/address-i…
Browse files Browse the repository at this point in the history
…deal-nav-review-v3

Address ideal nav review v3
  • Loading branch information
kosmydel committed Jan 15, 2024
2 parents 8e26531 + 1e8684b commit 8acc7a6
Show file tree
Hide file tree
Showing 34 changed files with 143 additions and 118 deletions.
2 changes: 1 addition & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,7 @@ const CONST = {
GUIDES_CALL_TASK_IDS: {
CONCIERGE_DM: 'NewExpensifyConciergeDM',
WORKSPACE_INITIAL: 'WorkspaceHome',
WORKSPACE_OVERVIEW: 'WorkspaceGeneralSettings',
WORKSPACE_OVERVIEW: 'WorkspaceOverview',
WORKSPACE_CARD: 'WorkspaceCorporateCards',
WORKSPACE_REIMBURSE: 'WorkspaceReimburseReceipts',
WORKSPACE_BILLS: 'WorkspacePayBills',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type ForceFullScreenViewProps from './types';

function ForceFullScreenView({children}: ForceFullScreenViewProps) {
return children;
}

ForceFullScreenView.displayName = 'ForceFullScreenView';

export default ForceFullScreenView;
18 changes: 18 additions & 0 deletions src/components/BlockingViews/ForceFullScreenView/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import {View} from 'react-native';
import useThemeStyles from '@hooks/useThemeStyles';
import type ForceFullScreenViewProps from './types';

function ForceFullScreenView({children, forceFullScreen = false}: ForceFullScreenViewProps) {
const styles = useThemeStyles();

if (forceFullScreen) {
return <View style={forceFullScreen && styles.forcedBlockingViewContainer}>{children}</View>;
}

return children;
}

ForceFullScreenView.displayName = 'ForceFullScreenView';

export default ForceFullScreenView;
7 changes: 7 additions & 0 deletions src/components/BlockingViews/ForceFullScreenView/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type ChildrenProps from '@src/types/utils/ChildrenProps';

type ForceFullScreenViewProps = ChildrenProps & {
forceFullScreen?: boolean;
};

export default ForceFullScreenViewProps;
9 changes: 7 additions & 2 deletions src/components/BlockingViews/FullPageNotFoundView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import variables from '@styles/variables';
import type {TranslationPaths} from '@src/languages/types';
import ROUTES from '@src/ROUTES';
import BlockingView from './BlockingView';
import ForceFullScreenView from './ForceFullScreenView';

type FullPageNotFoundViewProps = {
/** Child elements */
Expand Down Expand Up @@ -37,6 +38,9 @@ type FullPageNotFoundViewProps = {

/** Function to call when pressing the navigation link */
onLinkPress: () => void;

/** Whether we should force the full page view */
forceFullScreen?: boolean;
};

// eslint-disable-next-line rulesdir/no-negated-variables
Expand All @@ -50,13 +54,14 @@ function FullPageNotFoundView({
shouldShowLink = true,
shouldShowBackButton = true,
onLinkPress = () => Navigation.dismissModal(),
forceFullScreen = false,
}: FullPageNotFoundViewProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();

if (shouldShow) {
return (
<>
<ForceFullScreenView forceFullScreen={forceFullScreen}>
<HeaderWithBackButton
onBackButtonPress={onBackButtonPress}
shouldShowBackButton={shouldShowBackButton}
Expand All @@ -73,7 +78,7 @@ function FullPageNotFoundView({
onLinkPress={onLinkPress}
/>
</View>
</>
</ForceFullScreenView>
);
}

Expand Down
6 changes: 5 additions & 1 deletion src/components/ScreenWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ type ScreenWrapperProps = {
/** Whether to include padding bottom */
includeSafeAreaPaddingBottom?: boolean;

/** This overrides the above prop. It force disable the safe area bottom padding. */
shouldDisableSafeAreaPaddingBottom?: boolean;

/** Whether to include padding top */
includePaddingTop?: boolean;

Expand Down Expand Up @@ -103,6 +106,7 @@ function ScreenWrapper(
headerGapStyles,
children,
shouldShowOfflineIndicator = true,
shouldDisableSafeAreaPaddingBottom = false,
offlineIndicatorStyle,
style,
shouldDismissKeyboardBeforeClose = true,
Expand Down Expand Up @@ -202,7 +206,7 @@ function ScreenWrapper(
}

// We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked.
if (includeSafeAreaPaddingBottom || (isOffline && shouldShowOfflineIndicator)) {
if (!shouldDisableSafeAreaPaddingBottom && (includeSafeAreaPaddingBottom || (isOffline && shouldShowOfflineIndicator))) {
paddingStyle.paddingBottom = paddingBottom;
}

Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1566,7 +1566,7 @@ export default {
},
emptyWorkspace: {
title: 'Crea un espacio de trabajo',
subtitle: 'Administra gastos de empresa, emite tarjetas, envía facturas y mucho más.',
subtitle: 'En los espacios de trabajo podrás chatear con tu equipo, reembolsar gastos, emitir tarjetas, enviar y pagar facturas, y mucho más - todo en un mismo lugar.',
createAWorkspaceCTA: 'Comenzar',
features: {
trackAndCollect: 'Organiza recibos',
Expand Down
12 changes: 1 addition & 11 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type Screens = Partial<Record<Screen, () => React.ComponentType>>;
* Create a modal stack navigator with an array of sub-screens.
*
* @param screens key/value pairs where the key is the name of the screen and the value is a functon that returns the lazy-loaded component
* @param getScreenOptions optional function that returns the screen options, override the default options
*/
function createModalStackNavigator<TStackParams extends ParamListBase>(screens: Screens, getScreenOptions?: (styles: ThemeStyles) => StackNavigationOptions): React.ComponentType {
const ModalStackNavigator = createStackNavigator<TStackParams>();
Expand Down Expand Up @@ -184,8 +185,6 @@ const NewTeachersUniteNavigator = createModalStackNavigator<TeachersUniteNavigat

const AccountSettingsModalStackNavigator = createModalStackNavigator(
{
[SCREENS.SETTINGS.ROOT]: () => require('../../../pages/settings/InitialSettingsPage').default as React.ComponentType,
[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,
Expand All @@ -197,8 +196,6 @@ const AccountSettingsModalStackNavigator = createModalStackNavigator(
);

const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorParamList>({
[SCREENS.SETTINGS.SHARE_CODE]: () => require('../../../pages/ShareCodePage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.PRONOUNS]: () => require('../../../pages/settings/Profile/PronounsPage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.DISPLAY_NAME]: () => require('../../../pages/settings/Profile/DisplayNamePage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.TIMEZONE]: () => require('../../../pages/settings/Profile/TimezoneInitialPage').default as React.ComponentType,
Expand All @@ -211,16 +208,12 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: () => require('../../../pages/settings/Profile/Contacts/ContactMethodsPage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: () => require('../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: () => require('../../../pages/settings/Profile/Contacts/NewContactMethodPage').default as React.ComponentType,
[SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType,
[SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: () => require('../../../pages/settings/Preferences/PriorityModePage').default as React.ComponentType,
[SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: () => require('../../../pages/settings/Preferences/LanguagePage').default as React.ComponentType,
[SCREENS.SETTINGS.PREFERENCES.THEME]: () => require('../../../pages/settings/Preferences/ThemePage').default as React.ComponentType,
[SCREENS.SETTINGS.CLOSE]: () => require('../../../pages/settings/Security/CloseAccountPage').default as React.ComponentType,
[SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType,
[SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType,
[SCREENS.SETTINGS.APP_DOWNLOAD_LINKS]: () => require('../../../pages/settings/AppDownloadLinks').default as React.ComponentType,
[SCREENS.SETTINGS.LOUNGE_ACCESS]: () => require('../../../pages/settings/Profile/LoungeAccessPage').default as React.ComponentType,
[SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType,
[SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: () => require('../../../pages/settings/Profile/PersonalDetails/AddressPage').default as React.ComponentType,
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: () => require('../../../pages/settings/Wallet/ExpensifyCardPage').default as React.ComponentType,
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD]: () => require('../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default as React.ComponentType,
Expand All @@ -238,9 +231,6 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER]: () => require('../../../pages/settings/Profile/CustomStatus/StatusClearAfterPage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE]: () => require('../../../pages/settings/Profile/CustomStatus/SetDatePage').default as React.ComponentType,
[SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME]: () => require('../../../pages/settings/Profile/CustomStatus/SetTimePage').default as React.ComponentType,
[SCREENS.WORKSPACE.INITIAL]: () => require('../../../pages/workspace/WorkspaceInitialPage').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.RATE_AND_UNIT]: () => require('../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage').default as React.ComponentType,
[SCREENS.WORKSPACE.INVITE]: () => require('../../../pages/workspace/WorkspaceInvitePage').default as React.ComponentType,
[SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../pages/workspace/WorkspaceInviteMessagePage').default as React.ComponentType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Tab = createCustomBottomTabNavigator<BottomTabNavigatorParamList>();

const screenOptions: StackNavigationOptions = {
headerShown: false,
animationEnabled: false,
};

function BottomTabNavigator() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function FullScreenNavigator() {

return (
<View style={styles.rootNavigatorContainerStyles(isSmallScreenWidth)}>
<RootStack.Navigator isSmallScreenWidth={isSmallScreenWidth}>
<RootStack.Navigator>
<RootStack.Screen
name={SCREENS.SETTINGS.ROOT}
options={screenOptions.homeScreen}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function TopBar() {
<Search
placeholder={translate('sidebarScreen.buttonSearch')}
onPress={Session.checkIfActionIsAllowed(() => Navigation.navigate(ROUTES.SEARCH))}
containerStyle={styles.flexGrow1}
containerStyle={styles.flexShrink1}
/>
<SignInOrAvatarWithOptionalStatus />
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {DefaultNavigatorOptions, ParamListBase, StackActionHelpers, StackNa
import {createNavigatorFactory, StackRouter, useNavigationBuilder} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import {StackView} from '@react-navigation/stack';
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import ScreenWrapper from '@components/ScreenWrapper';
Expand All @@ -16,23 +15,6 @@ type CustomNavigatorProps = DefaultNavigatorOptions<ParamListBase, StackNavigati
initialRouteName: string;
};

const propTypes = {
/* Children for the useNavigationBuilder hook */
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,

/* initialRouteName for this navigator */
initialRouteName: PropTypes.oneOf([PropTypes.string, undefined]),

/* Screen options defined for this navigator */
// eslint-disable-next-line react/forbid-prop-types
screenOptions: PropTypes.object,
};

const defaultProps = {
initialRouteName: undefined,
screenOptions: undefined,
};

function getStateToRender(state: StackNavigationState<ParamListBase>): StackNavigationState<ParamListBase> {
const routesToRender = [state.routes.at(-1)] as NavigationStateRoute[];
// We need to render at least one HOME screen to make sure everything load properly.
Expand Down Expand Up @@ -84,8 +66,6 @@ function CustomBottomTabNavigator({initialRouteName, children, screenOptions, ..
);
}

CustomBottomTabNavigator.defaultProps = defaultProps;
CustomBottomTabNavigator.propTypes = propTypes;
CustomBottomTabNavigator.displayName = 'CustomBottomTabNavigator';

export default createNavigatorFactory(CustomBottomTabNavigator);
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';

type FullScreenNavigatorConfig = {
isSmallScreenWidth: boolean;
};

type FullScreenNavigatorRouterOptions = StackRouterOptions;

type FullScreenNavigatorProps = DefaultNavigatorOptions<ParamListBase, StackNavigationState<ParamListBase>, StackNavigationOptions, StackNavigationEventMap> & FullScreenNavigatorConfig;
type FullScreenNavigatorProps = DefaultNavigatorOptions<ParamListBase, StackNavigationState<ParamListBase>, StackNavigationOptions, StackNavigationEventMap>;

export type {FullScreenNavigatorConfig, FullScreenNavigatorProps, FullScreenNavigatorRouterOptions};
export type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions};
2 changes: 1 addition & 1 deletion src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ function goBack(fallbackRoute: Route = '', shouldEnforceFallback = false, should
*/
function closeFullScreen() {
const rootState = navigationRef.getRootState();
navigationRef.dispatch({...StackActions.pop(), target: rootState.key});
navigationRef.dispatch({...StackActions.popToTop(), target: rootState.key});
}

/**
Expand Down
13 changes: 13 additions & 0 deletions src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,17 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record<BottomTabName, CentralPaneName[]> = {
],
};

const generateCentralPaneToTabMapping = (): Record<CentralPaneName, BottomTabName> => {
const mapping: Record<CentralPaneName, BottomTabName> = {} as Record<CentralPaneName, BottomTabName>;
for (const [tabName, centralPaneNames] of Object.entries(TAB_TO_CENTRAL_PANE_MAPPING)) {
for (const centralPaneName of centralPaneNames) {
mapping[centralPaneName] = tabName as BottomTabName;
}
}
return mapping;
};

const CENTRAL_PANE_TO_TAB_MAPPING: Record<CentralPaneName, BottomTabName> = generateCentralPaneToTabMapping();

export {CENTRAL_PANE_TO_TAB_MAPPING};
export default TAB_TO_CENTRAL_PANE_MAPPING;
15 changes: 5 additions & 10 deletions src/libs/Navigation/getMatchingBottomTabRouteForState.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// import CONST from '@src/CONST';
import SCREENS from '@src/SCREENS';
import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute';
import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING';
import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING';
import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from './types';

// Get the route that matches the topmost central pane route in the navigation stack. e.g REPORT -> HOME
Expand All @@ -13,16 +13,11 @@ function getMatchingBottomTabRouteForState(state: State<RootStackParamList>): Na
return defaultRoute;
}

for (const [tabName, centralPaneNames] of Object.entries(TAB_TO_CENTRAL_PANE_MAPPING)) {
if (centralPaneNames.includes(topmostCentralPaneRoute.name)) {
if (tabName === SCREENS.WORKSPACE.INITIAL) {
return {name: tabName, params: topmostCentralPaneRoute.params};
}
return {name: tabName as BottomTabName};
}
const tabName = CENTRAL_PANE_TO_TAB_MAPPING[topmostCentralPaneRoute.name];
if (tabName === SCREENS.WORKSPACE.INITIAL) {
return {name: tabName, params: topmostCentralPaneRoute.params};
}

return defaultRoute;
return {name: tabName as BottomTabName} || defaultRoute;
}

export default getMatchingBottomTabRouteForState;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {NavigationState, PartialState} from '@react-navigation/native';
import SCREENS from '@src/SCREENS';

// Get the name of topmost report in the navigation stack.
function getTopmostCentralPaneName(state: NavigationState | PartialState<NavigationState>): string | undefined {
function getTopmostSettingsCentralPaneName(state: NavigationState | PartialState<NavigationState>): string | undefined {
if (!state) {
return;
}
Expand All @@ -16,4 +16,4 @@ function getTopmostCentralPaneName(state: NavigationState | PartialState<Navigat
return topmostCentralPane.state?.routes.at(-1)?.name;
}

export default getTopmostCentralPaneName;
export default getTopmostSettingsCentralPaneName;
8 changes: 7 additions & 1 deletion src/libs/Navigation/linkTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ function getActionForBottomTabNavigator(action: StackNavigationAction, state: Na
const params = action.payload.params as ActionPayloadParams;
const screen = params.screen;

// Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything.
const bottomTabCurrentTab = getTopmostBottomTabRoute(state);
if (bottomTabCurrentTab?.name === screen) {
return;
}

return {
type: CONST.NAVIGATION.ACTION_TYPE.PUSH,
payload: {
Expand Down Expand Up @@ -149,7 +155,7 @@ export default function linkTo(navigation: NavigationContainerRef<RootStackParam
const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState);

if (!actionForBottomTabNavigator) {
throw new Error('Could not get action for bottom tab navigator');
return;
}

root.dispatch(actionForBottomTabNavigator);
Expand Down
3 changes: 2 additions & 1 deletion src/pages/home/sidebar/AllSettingsScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ function AllSettingsScreen() {
<ScreenWrapper
testID={AllSettingsScreen.displayName}
includePaddingTop={false}
offlineIndicatorStyle={styles.offlineIndicatorBottomTabBar}
includeSafeAreaPaddingBottom={false}
shouldDisableSafeAreaPaddingBottom
>
<Breadcrumbs
breadcrumbs={[
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function BaseSidebarScreen(props) {
style={[styles.sidebar, Browser.isMobile() ? styles.userSelectNone : {}]}
testID={BaseSidebarScreen.displayName}
includePaddingTop={false}
offlineIndicatorStyle={styles.offlineIndicatorBottomTabBar}
shouldDisableSafeAreaPaddingBottom
>
{({insets}) => (
<View style={[styles.flex1]}>
Expand Down
Loading

0 comments on commit 8acc7a6

Please sign in to comment.