Skip to content

Commit

Permalink
Merge pull request #11 from software-mansion-labs/ideal-nav-merge-sea…
Browse files Browse the repository at this point in the history
…rch-bar

Ideal nav merge search bar
  • Loading branch information
adamgrzybowski authored Dec 21, 2023
2 parents 96a2875 + bd0d201 commit 5c19153
Show file tree
Hide file tree
Showing 20 changed files with 218 additions and 92 deletions.
2 changes: 1 addition & 1 deletion assets/images/new-expensify.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import EReceiptIcon from '@assets/images/eReceiptIcon.svg';
import Exclamation from '@assets/images/exclamation.svg';
import Exit from '@assets/images/exit.svg';
import Expand from '@assets/images/expand.svg';
import ExpensifyAppIcon from '@assets/images/expensify-app-icon.svg';
import ExpensifyFooterLogoVertical from '@assets/images/expensify-footer-logo-vertical.svg';
import ExpensifyFooterLogo from '@assets/images/expensify-footer-logo.svg';
import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
Expand Down Expand Up @@ -185,6 +186,7 @@ export {
EmptyStateAttachReceipt,
Exclamation,
Exit,
ExpensifyAppIcon,
ExpensifyCard,
ExpensifyWordmark,
ExpensifyFooterLogo,
Expand Down
1 change: 1 addition & 0 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,5 @@ function Icon({

Icon.displayName = 'Icon';

export type {IconProps};
export default Icon;
4 changes: 2 additions & 2 deletions src/components/IllustratedHeaderPageLayout.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import useTheme from '../hooks/useTheme';
import useThemeStyles from '../hooks/useThemeStyles';
import HeaderPageLayout from './HeaderPageLayout';
import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
import Lottie from './Lottie';
Expand Down
8 changes: 7 additions & 1 deletion src/components/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const defaultProps = {
shouldShowRightComponent: false,
titleWithTooltips: [],
shouldCheckActionAllowedOnPress: true,
isPaneMenu: false,
};

const MenuItem = React.forwardRef((props, ref) => {
Expand Down Expand Up @@ -234,6 +235,7 @@ const MenuItem = React.forwardRef((props, ref) => {
StyleUtils.getIconFillColor(
getButtonState(props.focused || isHovered, pressed, props.success, props.disabled, props.interactive),
true,
props.isPaneMenu,
)
}
/>
Expand Down Expand Up @@ -266,7 +268,11 @@ const MenuItem = React.forwardRef((props, ref) => {
height={props.iconHeight}
fill={
props.secondaryIconFill ||
StyleUtils.getIconFillColor(getButtonState(props.focused || isHovered, pressed, props.success, props.disabled, props.interactive), true)
StyleUtils.getIconFillColor(
getButtonState(props.focused || isHovered, pressed, props.success, props.disabled, props.interactive),
true,
props.isPaneMenu,
)
}
/>
</View>
Expand Down
86 changes: 64 additions & 22 deletions src/components/SubscriptAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,20 @@ import type {AvatarSource} from '@libs/UserUtils';
import CONST from '@src/CONST';
import {AvatarType} from '@src/types/onyx/OnyxCommon';
import Avatar from './Avatar';
import Icon, {IconProps} from './Icon';
import UserDetailsTooltip from './UserDetailsTooltip';

type SubIcon = {
/** Avatar source to display */
source: IconProps['src'];

/** Width of the icon */
width?: number;

/** Height of the icon */
height?: number;
};

type SubAvatar = {
/** Avatar source to display */
source?: AvatarSource;
Expand All @@ -31,23 +43,26 @@ type SubscriptAvatarProps = {
/** Avatar URL or icon */
mainAvatar?: SubAvatar;

/** Subscript avatar URL or icon */
secondaryAvatar?: SubAvatar;

/** Set the size of avatars */
size?: ValueOf<typeof CONST.AVATAR_SIZE>;

/** Background color used for subscript avatar border */
backgroundColor?: string;

/** Subscript avatar URL or icon */
secondaryAvatar?: SubAvatar;

/** Subscript icon type */
subscriptIcon?: SubIcon;

/** Removes margin from around the avatar, used for the chat view */
noMargin?: boolean;

/** Whether to show the tooltip */
showTooltip?: boolean;
};

function SubscriptAvatar({mainAvatar = {}, secondaryAvatar = {}, size = CONST.AVATAR_SIZE.DEFAULT, backgroundColor, noMargin = false, showTooltip = true}: SubscriptAvatarProps) {
function SubscriptAvatar({mainAvatar = {}, secondaryAvatar, subscriptIcon, size = CONST.AVATAR_SIZE.DEFAULT, backgroundColor, noMargin = false, showTooltip = true}: SubscriptAvatarProps) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
Expand All @@ -73,31 +88,58 @@ function SubscriptAvatar({mainAvatar = {}, secondaryAvatar = {}, size = CONST.AV
/>
</View>
</UserDetailsTooltip>
<UserDetailsTooltip
shouldRender={showTooltip}
accountID={secondaryAvatar.id ?? -1}
icon={secondaryAvatar}
>
{secondaryAvatar && (
<UserDetailsTooltip
shouldRender={showTooltip}
accountID={secondaryAvatar.id ?? -1}
icon={secondaryAvatar}
>
<View
style={[size === CONST.AVATAR_SIZE.SMALL_NORMAL ? styles.flex1 : {}, isSmall ? styles.secondAvatarSubscriptCompact : subscriptStyle]}
// Hover on overflowed part of icon will not work on Electron if dragArea is true
// https://stackoverflow.com/questions/56338939/hover-in-css-is-not-working-with-electron
dataSet={{dragArea: false}}
>
<Avatar
iconAdditionalStyles={[
StyleUtils.getAvatarBorderWidth(isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT),
StyleUtils.getBorderColorStyle(backgroundColor ?? theme.componentBG),
]}
source={secondaryAvatar.source}
size={isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT}
fill={theme.iconSuccessFill}
name={secondaryAvatar.name}
type={secondaryAvatar.type}
fallbackIcon={secondaryAvatar.fallbackIcon}
/>
</View>
</UserDetailsTooltip>
)}
{subscriptIcon && (
<View
style={[size === CONST.AVATAR_SIZE.SMALL_NORMAL ? styles.flex1 : {}, isSmall ? styles.secondAvatarSubscriptCompact : subscriptStyle]}
style={[
size === CONST.AVATAR_SIZE.SMALL_NORMAL ? styles.flex1 : {},
StyleUtils.getAvatarBorderStyle(CONST.AVATAR_SIZE.SMALL, CONST.ICON_TYPE_AVATAR),
StyleUtils.getAvatarBorderWidth(CONST.AVATAR_SIZE.SMALL),
// Nullish coalescing thinks that empty strings are truthy, thus I'm using OR operator
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
StyleUtils.getBorderColorStyle(backgroundColor || theme.sidebar),
styles.subscriptIcon,
styles.dFlex,
styles.justifyContentCenter,
]}
// Hover on overflowed part of icon will not work on Electron if dragArea is true
// https://stackoverflow.com/questions/56338939/hover-in-css-is-not-working-with-electron
dataSet={{dragArea: false}}
>
<Avatar
iconAdditionalStyles={[
StyleUtils.getAvatarBorderWidth(isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT),
StyleUtils.getBorderColorStyle(backgroundColor ?? theme.componentBG),
]}
source={secondaryAvatar.source}
size={isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT}
fill={theme.iconSuccessFill}
name={secondaryAvatar.name}
type={secondaryAvatar.type}
fallbackIcon={secondaryAvatar.fallbackIcon}
<Icon
src={subscriptIcon.source}
width={subscriptIcon.width}
height={subscriptIcon.height}
additionalStyles={styles.alignSelfCenter}
/>
</View>
</UserDetailsTooltip>
)}
</View>
);
}
Expand Down
30 changes: 30 additions & 0 deletions src/components/WorkspaceSwitcherButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import useLocalize from '@hooks/useLocalize';
import CONST from '@src/CONST';
import * as Expensicons from './Icon/Expensicons';
import {PressableWithFeedback} from './Pressable';
import SubscriptAvatar from './SubscriptAvatar';

function WorkspaceSwitcherButton() {
const {translate} = useLocalize();

return (
<PressableWithFeedback
accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={translate('common.workspaces')}
accessible
onPress={() => {}}
>
<SubscriptAvatar
mainAvatar={{source: Expensicons.ExpensifyAppIcon, name: 'Expensify', type: CONST.ICON_TYPE_AVATAR}}
subscriptIcon={{source: Expensicons.DownArrow, width: 8, height: 8}}
showTooltip={false}
noMargin
/>
</PressableWithFeedback>
);
}

WorkspaceSwitcherButton.displayName = 'WorkspaceSwitcherButton';

export default WorkspaceSwitcherButton;
3 changes: 3 additions & 0 deletions src/components/menuItemPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ const propTypes = {

/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress: PropTypes.bool,

/** Is this menu item in the settings pane */
isPaneMenu: PropTypes.bool,
};

export default propTypes;
1 change: 0 additions & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1996,7 +1996,6 @@ export default {
transactionDate: 'Transaction date',
},
breadcrumbs: {
// TODO-IDEAL: Verify translations in Spanish
chats: 'Chats',
},
referralProgram: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import * as Expensicons from '@components/Icon/Expensicons';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Search from '@components/Search';
import SubscriptAvatar from '@components/SubscriptAvatar';
import useLocalize from '@hooks/useLocalize';
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 ROUTES from '@src/ROUTES';

// TODO-IDEAL: isCreateMenuOpen wasn't used before
function TopBar({isCreateMenuOpen = false}) {
const styles = useThemeStyles();
const {translate} = useLocalize();

const showSearchPage = useCallback(() => {
if (isCreateMenuOpen) {
// Prevent opening Search page when click Search icon quickly after clicking FAB icon
return;
}

Navigation.navigate(ROUTES.SEARCH);
}, [isCreateMenuOpen]);

return (
<View
style={[styles.gap6, styles.flexRow, styles.ph5, styles.pv3, styles.justifyContentBetween, styles.alignItemsCenter]}
dataSet={{dragArea: true}}
>
<PressableWithFeedback role={CONST.ROLE.BUTTON}>
<SubscriptAvatar
mainAvatar={{source: Expensicons.ExpensifyAppIcon, name: 'Expensify', type: CONST.ICON_TYPE_AVATAR}}
subscriptIcon={{source: Expensicons.DownArrow, width: 8, height: 8}}
showTooltip={false}
noMargin
/>
</PressableWithFeedback>
<Search
placeholder={translate('sidebarScreen.buttonSearch')}
onPress={Session.checkIfActionIsAllowed(showSearchPage)}
style={{flex: 1}}
/>
<SignInOrAvatarWithOptionalStatus isCreateMenuOpen={isCreateMenuOpen} />
</View>
);
}

TopBar.displayName = 'TopBar';
TopBar.propTypes = {
isCreateMenuOpen: PropTypes.bool,
};
TopBar.defaultProps = {
isCreateMenuOpen: false,
};

export default TopBar;
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {View} from 'react-native';
import {NavigationStateRoute} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
import BottomTabBar from './BottomTabBar';
import TopBar from './TopBar';

type CustomNavigatorProps = DefaultNavigatorOptions<ParamListBase, StackNavigationState<ParamListBase>, StackNavigationOptions, StackNavigationEventMap> & {
initialRouteName: string;
Expand Down Expand Up @@ -67,6 +68,7 @@ function CustomBottomTabNavigator({initialRouteName, children, screenOptions, ..

return (
<View style={{flex: 1}}>
<TopBar />
<NavigationContent>
<StackView
// eslint-disable-next-line react/jsx-props-no-spreading
Expand Down
9 changes: 9 additions & 0 deletions src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ function goBack(fallbackRoute: Route, shouldEnforceFallback = false, shouldPopTo
navigationRef.current.goBack();
}

/**
* Close the full screen modal.
*/
function closeFullScreen() {
const rootState = navigationRef.getRootState();
navigationRef.dispatch({...StackActions.pop(), target: rootState.key});
}

/**
* Update route params for the specified route.
*/
Expand Down Expand Up @@ -307,6 +315,7 @@ export default {
getRouteNameFromStateEvent,
getTopmostReportActionId,
waitForProtectedRoutes,
closeFullScreen,
};

export {navigationRef};
Loading

0 comments on commit 5c19153

Please sign in to comment.