diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index bf48894beaab2..4acf197ba178b 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -7,6 +7,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportUtils from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserUtils'; +import * as UserUtils from '@libs/UserUtils'; import type {AvatarSizeName} from '@styles/utils'; import CONST from '@src/CONST'; import type {AvatarType} from '@src/types/onyx/OnyxCommon'; @@ -49,10 +50,13 @@ type AvatarProps = { /** Owner of the avatar. If user, displayName. If workspace, policy name */ name?: string; + + /** Optional account id if it's user avatar or policy id if it's workspace avatar */ + accountID?: number | string; }; function Avatar({ - source, + source: originalSource, imageStyles, iconAdditionalStyles, containerStyles, @@ -62,6 +66,7 @@ function Avatar({ fallbackIconTestID = '', type = CONST.ICON_TYPE_AVATAR, name = '', + accountID, }: AvatarProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -72,7 +77,7 @@ function Avatar({ useEffect(() => { setImageError(false); - }, [source]); + }, [originalSource]); const isWorkspace = type === CONST.ICON_TYPE_WORKSPACE; const iconSize = StyleUtils.getAvatarSize(size); @@ -81,14 +86,15 @@ function Avatar({ const iconStyle = imageStyles ? [StyleUtils.getAvatarStyle(size), styles.bgTransparent, imageStyles] : undefined; // We pass the color styles down to the SVG for the workspace and fallback avatar. - const useFallBackAvatar = imageError || source === Expensicons.FallbackAvatar || !source; + const source = isWorkspace ? originalSource : UserUtils.getAvatar(originalSource, Number(accountID)); + const useFallBackAvatar = imageError || !source || source === Expensicons.FallbackAvatar; const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(name) : fallbackIcon || Expensicons.FallbackAvatar; const fallbackAvatarTestID = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatarTestID(name) : fallbackIconTestID || 'SvgFallbackAvatar Icon'; const avatarSource = useFallBackAvatar ? fallbackAvatar : source; let iconColors; if (isWorkspace) { - iconColors = StyleUtils.getDefaultWorkspaceAvatarColor(name); + iconColors = StyleUtils.getDefaultWorkspaceAvatarColor(accountID?.toString() ?? ''); } else if (useFallBackAvatar) { iconColors = StyleUtils.getBackgroundColorAndFill(theme.buttonHoveredBG, theme.icon); } else { diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 0cbed7a2b4815..29d010d9c8034 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -182,6 +182,7 @@ function HeaderWithBackButton({ containerStyles={[StyleUtils.getWidthAndHeightStyle(StyleUtils.getAvatarSize(CONST.AVATAR_SIZE.DEFAULT)), styles.mr3]} source={policyAvatar?.source} name={policyAvatar?.name} + accountID={policyAvatar?.id} type={policyAvatar?.type} /> )} diff --git a/src/components/MentionSuggestions.tsx b/src/components/MentionSuggestions.tsx index 3866911fff9e8..b11ae4f5ecd8b 100644 --- a/src/components/MentionSuggestions.tsx +++ b/src/components/MentionSuggestions.tsx @@ -83,6 +83,7 @@ function MentionSuggestions({prefix, mentions, highlightedMentionIndex = 0, onSe source={item.icons[0].source} size={isIcon ? CONST.AVATAR_SIZE.MENTION_ICON : CONST.AVATAR_SIZE.SMALLER} name={item.icons[0].name} + accountID={item.icons[0].id} type={item.icons[0].type} fill={isIcon ? theme.success : undefined} fallbackIcon={item.icons[0].fallbackIcon} diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx index dedaba500a9c3..d5fcf66071799 100644 --- a/src/components/MultipleAvatars.tsx +++ b/src/components/MultipleAvatars.tsx @@ -156,6 +156,7 @@ function MultipleAvatars({ size={size} fill={icons[0].fill} name={icons[0].name} + accountID={icons[0].id} type={icons[0].type} fallbackIcon={icons[0].fallbackIcon} /> @@ -205,6 +206,7 @@ function MultipleAvatars({ source={icon.source ?? fallbackIcon} size={size} name={icon.name} + accountID={icon.id} type={icon.type} fallbackIcon={icon.fallbackIcon} /> @@ -263,6 +265,7 @@ function MultipleAvatars({ imageStyles={[singleAvatarStyle]} name={icons[0].name} type={icons[0].type} + accountID={icons[0].id} fallbackIcon={icons[0].fallbackIcon} /> @@ -282,6 +285,7 @@ function MultipleAvatars({ size={avatarSize} imageStyles={[singleAvatarStyle]} name={icons[1].name} + accountID={icons[1].id} type={icons[1].type} fallbackIcon={icons[1].fallbackIcon} /> diff --git a/src/components/RoomHeaderAvatars.tsx b/src/components/RoomHeaderAvatars.tsx index 9298062aa6f93..bdb4a0ac78ab8 100644 --- a/src/components/RoomHeaderAvatars.tsx +++ b/src/components/RoomHeaderAvatars.tsx @@ -47,6 +47,7 @@ function RoomHeaderAvatars({icons, reportID}: RoomHeaderAvatarsProps) { imageStyles={styles.avatarLarge} size={CONST.AVATAR_SIZE.LARGE} name={icons[0].name} + accountID={icons[0].id} type={icons[0].type} fallbackIcon={icons[0].fallbackIcon} /> @@ -82,6 +83,7 @@ function RoomHeaderAvatars({icons, reportID}: RoomHeaderAvatarsProps) { size={CONST.AVATAR_SIZE.LARGE} containerStyles={[...iconStyle, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]} name={icon.name} + accountID={icon.id} type={icon.type} fallbackIcon={icon.fallbackIcon} /> diff --git a/src/components/SubscriptAvatar.tsx b/src/components/SubscriptAvatar.tsx index 3e0f5fb9785ad..cc36657826f65 100644 --- a/src/components/SubscriptAvatar.tsx +++ b/src/components/SubscriptAvatar.tsx @@ -82,6 +82,7 @@ function SubscriptAvatar({ source={mainAvatar?.source} size={size} name={mainAvatar?.name} + accountID={mainAvatar?.id} type={mainAvatar?.type} fallbackIcon={mainAvatar?.fallbackIcon} /> @@ -108,6 +109,7 @@ function SubscriptAvatar({ size={isSmall ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT} fill={secondaryAvatar.fill} name={secondaryAvatar.name} + accountID={secondaryAvatar.id} type={secondaryAvatar.type} fallbackIcon={secondaryAvatar.fallbackIcon} /> diff --git a/src/components/UserDetailsTooltip/types.tsx b/src/components/UserDetailsTooltip/types.tsx index b362c44877a95..07c9310810be1 100644 --- a/src/components/UserDetailsTooltip/types.tsx +++ b/src/components/UserDetailsTooltip/types.tsx @@ -1,5 +1,5 @@ import type {AvatarSource} from '@libs/UserUtils'; -import type {AvatarType} from '@src/types/onyx/OnyxCommon'; +import type {AvatarType, Icon as IconType} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; type FallbackUserDetails = { @@ -16,22 +16,6 @@ type FallbackUserDetails = { type?: AvatarType; }; -type Icon = { - /** Source for the avatar. Can be a URL or an icon. */ - source?: AvatarSource; - - /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. - * If the avatar is type === workspace, this fallback icon will be ignored and decided based on the name prop. - */ - fallbackIcon?: AvatarSource; - - /** Denotes whether it is an avatar or a workspace avatar */ - type?: AvatarType; - - /** Owner of the avatar. If user, displayName. If workspace, policy name */ - name?: string; -}; - type UserDetailsTooltipProps = ChildrenProps & { /** User's Account ID */ accountID: number; @@ -40,7 +24,7 @@ type UserDetailsTooltipProps = ChildrenProps & { fallbackUserDetails?: FallbackUserDetails; /** Optionally, pass in the icon instead of calculating it. If defined, will take precedence. */ - icon?: Icon; + icon?: IconType; /** The accountID of the copilot who took this action on behalf of the user */ delegateAccountID?: number; diff --git a/src/components/WorkspaceSwitcherButton.tsx b/src/components/WorkspaceSwitcherButton.tsx index 2b9b3480f96de..118fcd0f10a93 100644 --- a/src/components/WorkspaceSwitcherButton.tsx +++ b/src/components/WorkspaceSwitcherButton.tsx @@ -26,7 +26,7 @@ function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) { const pressableRef = useRef(null); - const {source, name, type} = useMemo(() => { + const {source, name, type, id} = useMemo(() => { if (!policy) { return {source: Expensicons.ExpensifyAppIcon, name: CONST.WORKSPACE_SWITCHER.NAME, type: CONST.ICON_TYPE_AVATAR}; } @@ -36,6 +36,7 @@ function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) { source: avatar, name: policy?.name ?? '', type: CONST.ICON_TYPE_WORKSPACE, + id: policy?.id ?? '', }; }, [policy]); @@ -55,7 +56,7 @@ function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) { > {({hovered}) => ( , policy: OnyxEntry = source: policyExpenseChatAvatarSource ?? '', type: CONST.ICON_TYPE_WORKSPACE, name: workspaceName, - id: -1, + id: report?.policyID, }; return workspaceIcon; } @@ -1920,7 +1920,7 @@ function getIcons( source: policyExpenseChatAvatarSource, type: CONST.ICON_TYPE_WORKSPACE, name: domainName ?? '', - id: -1, + id: report?.policyID, }; return [domainIcon]; } diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index b90d129f91eba..a2768d71d42a1 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -118,6 +118,7 @@ function WorkspaceSwitcherPage() { fallbackIcon: Expensicons.FallbackWorkspaceAvatar, name: policy?.name, type: CONST.ICON_TYPE_WORKSPACE, + id: policy?.id, }, ], isBold: hasUnreadData(policy?.id), diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index 421faae66bf07..de9e0b6a6ece9 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -1,6 +1,5 @@ import React, {memo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; -import type {AvatarProps} from '@components/Avatar'; import RenderHTML from '@components/RenderHTML'; import Text from '@components/Text'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; @@ -39,7 +38,7 @@ type ReportActionItemFragmentProps = { delegateAccountID?: number; /** icon */ - actorIcon?: AvatarProps; + actorIcon?: OnyxCommon.Icon; /** Whether the comment is a thread parent message/the first message in a thread */ isThreadParentMessage?: boolean; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 042f217e057db..bed9c84c26169 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -203,6 +203,7 @@ function ReportActionItemSingle({ source={icon.source} type={icon.type} name={icon.name} + accountID={icon.id} fallbackIcon={fallbackIcon} /> diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 4913a7db71b2e..ee00db8d0ac7b 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -315,6 +315,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc source: avatar, name: policy?.name ?? '', type: CONST.ICON_TYPE_WORKSPACE, + id: policy.id ?? '', }; }, [policy]); diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index b73c6c0d70626..ea54ae0648881 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -83,10 +83,11 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi fallbackIcon={Expensicons.FallbackWorkspaceAvatar} size={CONST.AVATAR_SIZE.XLARGE} name={policyName} + accountID={policy?.id ?? ''} type={CONST.ICON_TYPE_WORKSPACE} /> ), - [policy?.avatar, policyName, styles.alignSelfCenter, styles.avatarXLarge], + [policy?.avatar, policy?.id, policyName, styles.alignSelfCenter, styles.avatarXLarge], ); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index f0cb062fb4b31..050fb72b02acf 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -212,6 +212,7 @@ function WorkspacesListPage({policies, reimbursementAccount, reports, session}: {({hovered}) => ( diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index cc82a80a4909e..d6f05f1f3b760 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -270,8 +270,8 @@ function getAvatarBorderStyle(size: AvatarSizeName, type: string): ViewStyle { /** * Helper method to return workspace avatar color styles */ -function getDefaultWorkspaceAvatarColor(workspaceName: string): ViewStyle { - const colorHash = UserUtils.hashText(workspaceName.trim(), workspaceColorOptions.length); +function getDefaultWorkspaceAvatarColor(text: string): ViewStyle { + const colorHash = UserUtils.hashText(text.trim(), workspaceColorOptions.length); return workspaceColorOptions[colorHash]; } diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 8b96a89a2a1b9..c4a3afc3e0b93 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -25,10 +25,10 @@ type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPA type Icon = { /** Avatar source to display */ - source: AvatarSource; + source?: AvatarSource; /** Denotes whether it is an avatar or a workspace avatar */ - type: AvatarType; + type?: AvatarType; /** Owner of the avatar. If user, displayName. If workspace, policy name */ name?: string;