Skip to content

Commit

Permalink
Merge pull request #20512 from Expensify/georgia-updateAvatars
Browse files Browse the repository at this point in the history
Update Avatar Patterns for LHN
  • Loading branch information
chiragsalian authored Jul 7, 2023
2 parents 28561c3 + 3776931 commit 89a5759
Show file tree
Hide file tree
Showing 19 changed files with 244 additions and 151 deletions.
1 change: 1 addition & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,7 @@ const CONST = {
LARGE_BORDERED: 'large-bordered',
HEADER: 'header',
MENTION_ICON: 'mention-icon',
SMALL_NORMAL: 'small-normal',
},
AVATAR_ROW_SIZE: {
DEFAULT: 4,
Expand Down
4 changes: 2 additions & 2 deletions src/components/Avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const propTypes = {
/** Denotes whether it is an avatar or a workspace avatar */
type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]),

/** Owner of the avatar, typically a login email or workspace name */
/** Owner of the avatar. If user, displayName. If workspace, policy name */
name: PropTypes.string,
};

Expand Down Expand Up @@ -76,7 +76,7 @@ function Avatar(props) {
const imageStyle =
props.imageStyles && props.imageStyles.length
? [StyleUtils.getAvatarStyle(props.size), ...props.imageStyles, StyleUtils.getAvatarBorderRadius(props.size, props.type)]
: [StyleUtils.getAvatarStyle(props.size), styles.noBorderRadius];
: [StyleUtils.getAvatarStyle(props.size), StyleUtils.getAvatarBorderStyle(props.size, props.type)];

const iconStyle = props.imageStyles && props.imageStyles.length ? [StyleUtils.getAvatarStyle(props.size), styles.bgTransparent, ...props.imageStyles] : undefined;

Expand Down
2 changes: 0 additions & 2 deletions src/components/AvatarWithDisplayName.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ function AvatarWithDisplayName(props) {
backgroundColor={themeColors.highlightBG}
mainAvatar={icons[0]}
secondaryAvatar={icons[1]}
mainTooltip={props.report.ownerEmail}
secondaryTooltip={subtitle}
size={props.size}
/>
) : (
Expand Down
14 changes: 2 additions & 12 deletions src/components/LHNOptionsList/OptionRowLHN.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import SubscriptAvatar from '../SubscriptAvatar';
import CONST from '../../CONST';
import themeColors from '../../styles/themes/default';
import SidebarUtils from '../../libs/SidebarUtils';
import TextPill from '../TextPill';
import OfflineWithFeedback from '../OfflineWithFeedback';
import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu';
Expand Down Expand Up @@ -83,7 +82,6 @@ function OptionRowLHN(props) {
const textStyle = props.isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText;
const textUnreadStyle = optionItem.isUnread ? [textStyle, styles.sidebarLinkTextBold] : [textStyle];
const displayNameStyle = StyleUtils.combineStyles([styles.optionDisplayName, styles.optionDisplayNameCompact, styles.pre, ...textUnreadStyle], props.style);
const textPillStyle = props.isFocused ? [styles.ml1, StyleUtils.getBackgroundColorWithOpacityStyle(themeColors.icon, 0.5)] : [styles.ml1];
const alternateTextStyle = StyleUtils.combineStyles(
props.viewMode === CONST.OPTION_MODE.COMPACT
? [textStyle, styles.optionAlternateText, styles.pre, styles.textLabelSupporting, styles.optionAlternateTextCompact, styles.ml2]
Expand All @@ -101,6 +99,7 @@ function OptionRowLHN(props) {
const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;

const hasBrickError = optionItem.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
const defaultSubscriptSize = optionItem.isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT;
const shouldShowGreenDotIndicator =
!hasBrickError &&
(optionItem.isUnreadWithMention ||
Expand Down Expand Up @@ -172,9 +171,7 @@ function OptionRowLHN(props) {
backgroundColor={props.isFocused ? themeColors.activeComponentBG : themeColors.sidebar}
mainAvatar={optionItem.icons[0]}
secondaryAvatar={optionItem.icons[1]}
mainTooltip={optionItem.ownerEmail}
secondaryTooltip={optionItem.subtitle}
size={props.viewMode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
size={props.viewMode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : defaultSubscriptSize}
/>
) : (
<MultipleAvatars
Expand Down Expand Up @@ -202,13 +199,6 @@ function OptionRowLHN(props) {
optionItem.isChatRoom || optionItem.isPolicyExpenseChat || optionItem.isTaskReport || optionItem.isThread || optionItem.isMoneyRequestReport
}
/>
{optionItem.isChatRoom && !optionItem.isThread && (
<TextPill
style={textPillStyle}
accessibilityLabel={props.translate('accessibilityHints.workspaceName')}
text={optionItem.subtitle}
/>
)}
</View>
{optionItem.alternateText ? (
<Text
Expand Down
31 changes: 16 additions & 15 deletions src/components/MultipleAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, {memo, useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import styles from '../styles/styles';
import Avatar from './Avatar';
import Tooltip from './Tooltip';
Expand All @@ -13,7 +12,6 @@ import CONST from '../CONST';
import variables from '../styles/variables';
import avatarPropTypes from './avatarPropTypes';
import UserDetailsTooltip from './UserDetailsTooltip';
import * as ReportUtils from '../libs/ReportUtils';

const propTypes = {
/** Array of avatar URLs or icons */
Expand Down Expand Up @@ -76,7 +74,7 @@ const defaultProps = {
function MultipleAvatars(props) {
const [avatarRows, setAvatarRows] = useState([props.icons]);
let avatarContainerStyles = props.size === CONST.AVATAR_SIZE.SMALL ? [styles.emptyAvatarSmall, styles.emptyAvatarMarginSmall] : [styles.emptyAvatar, styles.emptyAvatarMargin];
const singleAvatarStyles = props.size === CONST.AVATAR_SIZE.SMALL ? styles.singleAvatarSmall : styles.singleAvatar;
const singleAvatarStyle = props.size === CONST.AVATAR_SIZE.SMALL ? styles.singleAvatarSmall : styles.singleAvatar;
const secondAvatarStyles = [props.size === CONST.AVATAR_SIZE.SMALL ? styles.secondAvatarSmall : styles.secondAvatar, ...props.secondAvatarStyle];
const tooltipTexts = props.shouldShowTooltip ? _.pluck(props.icons, 'name') : [''];

Expand Down Expand Up @@ -113,11 +111,7 @@ function MultipleAvatars(props) {
return (
<UserDetailsTooltip
accountID={props.icons[0].id}
fallbackUserDetails={{
displayName: ReportUtils.getDisplayNameForParticipant(props.icons[0].id),
login: lodashGet(props.icons[0], 'name', tooltipTexts[0]),
avatar: lodashGet(props.icons[0], 'source', ''),
}}
icon={props.icons[0]}
>
<View style={avatarContainerStyles}>
<Avatar
Expand Down Expand Up @@ -163,6 +157,7 @@ function MultipleAvatars(props) {
<UserDetailsTooltip
key={`stackedAvatars-${index}`}
accountID={icon.id}
icon={icon}
>
<View
style={[
Expand Down Expand Up @@ -227,37 +222,43 @@ function MultipleAvatars(props) {
))
) : (
<View style={avatarContainerStyles}>
<View style={singleAvatarStyles}>
<UserDetailsTooltip accountID={props.icons[0].id}>
<View style={[singleAvatarStyle, props.icons[0].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(props.size, props.icons[0].type) : {}]}>
<UserDetailsTooltip
accountID={props.icons[0].id}
icon={props.icons[0]}
>
{/* View is necessary for tooltip to show for multiple avatars in LHN */}
<View>
<Avatar
source={props.icons[0].source || props.fallbackIcon}
fill={themeColors.iconSuccessFill}
size={props.isFocusMode ? CONST.AVATAR_SIZE.MID_SUBSCRIPT : CONST.AVATAR_SIZE.SMALLER}
imageStyles={[singleAvatarStyles]}
imageStyles={[singleAvatarStyle]}
name={props.icons[0].name}
type={props.icons[0].type}
/>
</View>
</UserDetailsTooltip>
<View style={secondAvatarStyles}>
<View style={[...secondAvatarStyles, props.icons[1].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(props.size, props.icons[1].type) : {}]}>
{props.icons.length === 2 ? (
<UserDetailsTooltip accountID={props.icons[1].id}>
<UserDetailsTooltip
accountID={props.icons[1].id}
icon={props.icons[1]}
>
<View>
<Avatar
source={props.icons[1].source || props.fallbackIcon}
fill={themeColors.iconSuccessFill}
size={props.isFocusMode ? CONST.AVATAR_SIZE.MID_SUBSCRIPT : CONST.AVATAR_SIZE.SMALLER}
imageStyles={[singleAvatarStyles]}
imageStyles={[singleAvatarStyle]}
name={props.icons[1].name}
type={props.icons[1].type}
/>
</View>
</UserDetailsTooltip>
) : (
<Tooltip text={tooltipTexts.slice(1).join(', ')}>
<View style={[singleAvatarStyles, styles.alignItemsCenter, styles.justifyContentCenter]}>
<View style={[singleAvatarStyle, styles.alignItemsCenter, styles.justifyContentCenter]}>
<Text
selectable={false}
style={props.size === CONST.AVATAR_SIZE.SMALL ? styles.avatarInnerTextSmall : styles.avatarInnerText}
Expand Down
4 changes: 2 additions & 2 deletions src/components/OptionRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class OptionRow extends Component {
const hoveredBackgroundColor = this.props.hoverStyle && this.props.hoverStyle.backgroundColor ? this.props.hoverStyle.backgroundColor : this.props.backgroundColor;
const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;
const isMultipleParticipant = lodashGet(this.props.option, 'participantsList.length', 0) > 1;
const defaultSubscriptSize = this.props.option.isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT;

// We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade.
const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(
Expand Down Expand Up @@ -193,9 +194,8 @@ class OptionRow extends Component {
<SubscriptAvatar
mainAvatar={this.props.option.icons[0]}
secondaryAvatar={this.props.option.icons[1]}
mainTooltip={this.props.option.ownerEmail}
secondaryTooltip={this.props.option.subtitle}
backgroundColor={hovered && !this.props.optionIsFocused ? hoveredBackgroundColor : subscriptColor}
size={defaultSubscriptSize}
/>
) : (
<MultipleAvatars
Expand Down
42 changes: 21 additions & 21 deletions src/components/SubscriptAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React, {memo} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import styles from '../styles/styles';
import Tooltip from './Tooltip';
import themeColors from '../styles/themes/default';
import Avatar from './Avatar';
import CONST from '../CONST';
import * as StyleUtils from '../styles/StyleUtils';
import avatarPropTypes from './avatarPropTypes';
import UserDetailsTooltip from './UserDetailsTooltip';

const propTypes = {
/** Avatar URL or icon */
Expand All @@ -17,12 +18,6 @@ const propTypes = {
/** Subscript avatar URL or icon */
secondaryAvatar: avatarPropTypes,

/** Tooltip for the main avatar */
mainTooltip: PropTypes.string,

/** Tooltip for the subscript avatar */
secondaryTooltip: PropTypes.string,

/** Set the size of avatars */
size: PropTypes.oneOf(_.values(CONST.AVATAR_SIZE)),

Expand All @@ -34,8 +29,6 @@ const propTypes = {
};

const defaultProps = {
mainTooltip: '',
secondaryTooltip: '',
size: CONST.AVATAR_SIZE.DEFAULT,
backgroundColor: themeColors.componentBG,
mainAvatar: {},
Expand All @@ -44,43 +37,50 @@ const defaultProps = {
};

function SubscriptAvatar(props) {
const containerStyle = props.size === CONST.AVATAR_SIZE.SMALL ? styles.emptyAvatarSmall : styles.emptyAvatar;

const isSmall = props.size === CONST.AVATAR_SIZE.SMALL;
const subscriptSyle = props.size === CONST.AVATAR_SIZE.SMALL_NORMAL ? styles.secondAvatarSubscriptSmallNormal : styles.secondAvatarSubscript;
const containerStyle = isSmall ? styles.emptyAvatarSmall : styles.emptyAvatar;
// Default the margin style to what is normal for small or normal sized avatars
let marginStyle = props.size === CONST.AVATAR_SIZE.SMALL ? styles.emptyAvatarMarginSmall : styles.emptyAvatarMargin;
let marginStyle = isSmall ? styles.emptyAvatarMarginSmall : styles.emptyAvatarMargin;

// Some views like the chat view require that there be no margins
if (props.noMargin) {
marginStyle = {};
}
return (
<View style={[containerStyle, marginStyle]}>
<Tooltip text={props.mainTooltip}>
<UserDetailsTooltip
accountID={lodashGet(props.mainAvatar, 'id', -1)}
icon={props.mainAvatar}
>
<View>
<Avatar
source={props.mainAvatar.source}
size={props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
size={props.size || CONST.AVATAR_SIZE.DEFAULT}
name={props.mainAvatar.name}
type={props.mainAvatar.type}
/>
</View>
</Tooltip>
<Tooltip text={props.secondaryTooltip}>
<View>
</UserDetailsTooltip>
<UserDetailsTooltip
accountID={lodashGet(props.secondaryAvatar, 'id', -1)}
icon={props.secondaryAvatar}
>
<View style={props.size === CONST.AVATAR_SIZE.SMALL_NORMAL ? styles.flex1 : {}}>
<Avatar
containerStyles={[props.size === CONST.AVATAR_SIZE.SMALL ? styles.secondAvatarSubscriptCompact : styles.secondAvatarSubscript]}
containerStyles={[props.size === CONST.AVATAR_SIZE.SMALL ? styles.secondAvatarSubscriptCompact : subscriptSyle]}
iconAdditionalStyles={[
StyleUtils.getAvatarBorderWidth(props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT),
StyleUtils.getAvatarBorderWidth(isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT),
StyleUtils.getBorderColorStyle(props.backgroundColor),
]}
source={props.secondaryAvatar.source}
size={props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT}
size={isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT}
fill={themeColors.iconSuccessFill}
name={props.secondaryAvatar.name}
type={props.secondaryAvatar.type}
/>
</View>
</Tooltip>
</UserDetailsTooltip>
</View>
);
}
Expand Down
22 changes: 13 additions & 9 deletions src/components/UserDetailsTooltip/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ONYXKEYS from '../../ONYXKEYS';
import withLocalize from '../withLocalize';
import compose from '../../libs/compose';
import * as UserUtils from '../../libs/UserUtils';
import CONST from '../../CONST';
import * as LocalePhoneNumber from '../../libs/LocalePhoneNumber';

function UserDetailsTooltip(props) {
Expand All @@ -32,27 +33,30 @@ function UserDetailsTooltip(props) {
userAccountID = props.delegateAccountID;
}

let title = String(userDisplayName).trim() ? userDisplayName : '';
const subtitle = (userLogin || '').trim() && !_.isEqual(LocalePhoneNumber.formatPhoneNumber(userLogin || ''), userDisplayName) ? Str.removeSMSDomain(userLogin) : '';
if (props.icon && props.icon.type === CONST.ICON_TYPE_WORKSPACE) {
title = props.icon.name;
}
const renderTooltipContent = useCallback(
() => (
<View style={[styles.alignItemsCenter, styles.ph2, styles.pv2]}>
<View style={styles.emptyAvatar}>
<Avatar
containerStyles={[styles.actionAvatar]}
source={UserUtils.getAvatar(userAvatar, userAccountID)}
source={props.icon ? props.icon.source : UserUtils.getAvatar(userAvatar, userAccountID)}
type={props.icon ? props.icon.type : CONST.ICON_TYPE_AVATAR}
name={props.icon ? props.icon.name : userLogin}
/>
</View>

<Text style={[styles.mt2, styles.textMicroBold, styles.textReactionSenders, styles.textAlignCenter]}>{userDisplayName}</Text>

<Text style={[styles.textMicro, styles.fontColorReactionLabel]}>
{(userLogin || '').trim() && !_.isEqual(LocalePhoneNumber.formatPhoneNumber(userLogin || ''), userDisplayName) ? Str.removeSMSDomain(userLogin) : ''}
</Text>
<Text style={[styles.mt2, styles.textMicroBold, styles.textReactionSenders, styles.textAlignCenter]}>{title}</Text>
<Text style={[styles.textMicro, styles.fontColorReactionLabel]}>{subtitle}</Text>
</View>
),
[userAvatar, userDisplayName, userLogin, userAccountID],
[props.icon, userAvatar, userAccountID, userLogin, title, subtitle],
);

if (!userDisplayName && !userLogin) {
if (!props.icon && !userDisplayName && !userLogin) {
return props.children;
}

Expand Down
Loading

0 comments on commit 89a5759

Please sign in to comment.