From 280909e3327a95d775765024e4dfbf7eadee312b Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 8 Nov 2023 11:38:44 +0100
Subject: [PATCH 1/6] [TS migration] Migrate 'MultipleAvatars.js' component

---
 ...MultipleAvatars.js => MultipleAvatars.tsx} | 242 ++++++++++--------
 src/components/Tooltip/index.js               |   2 +-
 src/components/UserDetailsTooltip/index.js    |   2 +-
 src/libs/UserUtils.ts                         |   3 +
 src/styles/StyleUtils.ts                      |  14 +-
 5 files changed, 144 insertions(+), 119 deletions(-)
 rename src/components/{MultipleAvatars.js => MultipleAvatars.tsx} (57%)

diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.tsx
similarity index 57%
rename from src/components/MultipleAvatars.js
rename to src/components/MultipleAvatars.tsx
index 209540189b69..00c591e3a580 100644
--- a/src/components/MultipleAvatars.js
+++ b/src/components/MultipleAvatars.tsx
@@ -1,77 +1,85 @@
-import PropTypes from 'prop-types';
 import React, {memo, useMemo} from 'react';
-import {View} from 'react-native';
-import _ from 'underscore';
+import {StyleProp, View, ViewStyle} from 'react-native';
+import {ValueOf} from 'type-fest';
+import {AvatarSource} from '@libs/UserUtils';
 import styles from '@styles/styles';
 import * as StyleUtils from '@styles/StyleUtils';
 import themeColors from '@styles/themes/default';
 import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import Avatar from './Avatar';
-import avatarPropTypes from './avatarPropTypes';
 import Text from './Text';
 import Tooltip from './Tooltip';
 import UserDetailsTooltip from './UserDetailsTooltip';
 
-const propTypes = {
+type AvatarType = {
+    /** Avatar source to display */
+    source?: AvatarSource;
+
+    /** Denotes whether it is an avatar or a workspace avatar */
+    type?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
+
+    /** Owner of the avatar. If user, displayName. If workspace, policy name */
+    name?: string;
+
+    /** Avatar id */
+    id?: number | string;
+
+    /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
+    fallbackIcon?: AvatarSource;
+};
+
+type MultipleAvatarsProps = {
     /** Array of avatar URLs or icons */
-    icons: PropTypes.arrayOf(avatarPropTypes),
+    icons: AvatarType[];
 
     /** Set the size of avatars */
-    size: PropTypes.oneOf(_.values(CONST.AVATAR_SIZE)),
+    size: ValueOf<typeof CONST.AVATAR_SIZE>;
 
     /** Style for Second Avatar */
-    // eslint-disable-next-line react/forbid-prop-types
-    secondAvatarStyle: PropTypes.arrayOf(PropTypes.object),
+    secondAvatarStyle: StyleProp<ViewStyle>;
 
     /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
-    fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
+    fallbackIcon?: AvatarSource;
 
     /** Prop to identify if we should load avatars vertically instead of diagonally */
-    shouldStackHorizontally: PropTypes.bool,
+    shouldStackHorizontally?: boolean;
 
     /** Prop to identify if we should display avatars in rows */
-    shouldDisplayAvatarsInRows: PropTypes.bool,
+    shouldDisplayAvatarsInRows?: boolean;
 
     /** Whether the avatars are hovered */
-    isHovered: PropTypes.bool,
+    isHovered?: boolean;
 
     /** Whether the avatars are in an element being pressed */
-    isPressed: PropTypes.bool,
+    isPressed?: boolean;
 
     /** Whether #focus mode is on */
-    isFocusMode: PropTypes.bool,
+    isFocusMode?: boolean;
 
     /** Whether avatars are displayed within a reportAction */
-    isInReportAction: PropTypes.bool,
+    isInReportAction?: boolean;
 
     /** Whether to show the toolip text */
-    shouldShowTooltip: PropTypes.bool,
+    shouldShowTooltip?: boolean;
 
     /** Whether avatars are displayed with the highlighted background color instead of the app background color. This is primarily the case for IOU previews. */
-    shouldUseCardBackground: PropTypes.bool,
+    shouldUseCardBackground?: boolean;
 
     /** Prop to limit the amount of avatars displayed horizontally */
-    maxAvatarsInRow: PropTypes.number,
+    maxAvatarsInRow?: number;
 };
 
-const defaultProps = {
-    icons: [],
-    size: CONST.AVATAR_SIZE.DEFAULT,
-    secondAvatarStyle: [StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)],
-    fallbackIcon: undefined,
-    shouldStackHorizontally: false,
-    shouldDisplayAvatarsInRows: false,
-    isHovered: false,
-    isPressed: false,
-    isFocusMode: false,
-    isInReportAction: false,
-    shouldShowTooltip: true,
-    shouldUseCardBackground: false,
-    maxAvatarsInRow: CONST.AVATAR_ROW_SIZE.DEFAULT,
+type AvatarStyles = {
+    singleAvatarStyle: ViewStyle;
+    secondAvatarStyles: ViewStyle;
 };
 
-const avatarSizeToStylesMap = {
+type AvatarSizeToStyles = typeof CONST.AVATAR_SIZE.SMALL | typeof CONST.AVATAR_SIZE.LARGE | typeof CONST.AVATAR_SIZE.DEFAULT;
+
+type AvatarSizeToStylesMap = Record<AvatarSizeToStyles, AvatarStyles>;
+
+const avatarSizeToStylesMap: AvatarSizeToStylesMap = {
     [CONST.AVATAR_SIZE.SMALL]: {
         singleAvatarStyle: styles.singleAvatarSmall,
         secondAvatarStyles: styles.secondAvatarSmall,
@@ -80,78 +88,93 @@ const avatarSizeToStylesMap = {
         singleAvatarStyle: styles.singleAvatarMedium,
         secondAvatarStyles: styles.secondAvatarMedium,
     },
-    default: {
+    [CONST.AVATAR_SIZE.DEFAULT]: {
         singleAvatarStyle: styles.singleAvatar,
         secondAvatarStyles: styles.secondAvatar,
     },
 };
-function MultipleAvatars(props) {
-    let avatarContainerStyles = StyleUtils.getContainerStyles(props.size, props.isInReportAction);
-    const {singleAvatarStyle, secondAvatarStyles} = useMemo(() => avatarSizeToStylesMap[props.size] || avatarSizeToStylesMap.default, [props.size]);
 
-    const tooltipTexts = props.shouldShowTooltip ? _.pluck(props.icons, 'name') : [''];
+function MultipleAvatars({
+    fallbackIcon,
+    icons = [],
+    size = CONST.AVATAR_SIZE.DEFAULT,
+    secondAvatarStyle = [StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)],
+    shouldStackHorizontally = false,
+    shouldDisplayAvatarsInRows = false,
+    isHovered = false,
+    isPressed = false,
+    isFocusMode = false,
+    isInReportAction = false,
+    shouldShowTooltip = true,
+    shouldUseCardBackground = false,
+    maxAvatarsInRow = CONST.AVATAR_ROW_SIZE.DEFAULT,
+}: MultipleAvatarsProps) {
+    let avatarContainerStyles = StyleUtils.getContainerStyles(size, isInReportAction);
+    const {singleAvatarStyle, secondAvatarStyles} = useMemo(() => avatarSizeToStylesMap[size as AvatarSizeToStyles] ?? avatarSizeToStylesMap.default, [size]);
+
+    const tooltipTexts = shouldShowTooltip ? icons.map((icon) => icon.name) : [''];
     const avatarSize = useMemo(() => {
-        if (props.isFocusMode) {
+        if (isFocusMode) {
             return CONST.AVATAR_SIZE.MID_SUBSCRIPT;
         }
 
-        if (props.size === CONST.AVATAR_SIZE.LARGE) {
+        if (size === CONST.AVATAR_SIZE.LARGE) {
             return CONST.AVATAR_SIZE.MEDIUM;
         }
 
         return CONST.AVATAR_SIZE.SMALLER;
-    }, [props.isFocusMode, props.size]);
+    }, [isFocusMode, size]);
 
     const avatarRows = useMemo(() => {
         // If we're not displaying avatars in rows or the number of icons is less than or equal to the max avatars in a row, return a single row
-        if (!props.shouldDisplayAvatarsInRows || props.icons.length <= props.maxAvatarsInRow) {
-            return [props.icons];
+        if (!shouldDisplayAvatarsInRows || icons.length <= maxAvatarsInRow) {
+            return [icons];
         }
 
         // Calculate the size of each row
-        const rowSize = Math.min(Math.ceil(props.icons.length / 2), props.maxAvatarsInRow);
+        const rowSize = Math.min(Math.ceil(icons.length / 2), maxAvatarsInRow);
 
         // Slice the icons array into two rows
-        const firstRow = props.icons.slice(rowSize);
-        const secondRow = props.icons.slice(0, rowSize);
+        const firstRow = icons.slice(rowSize);
+        const secondRow = icons.slice(0, rowSize);
 
         // Update the state with the two rows as an array
         return [firstRow, secondRow];
-    }, [props.icons, props.maxAvatarsInRow, props.shouldDisplayAvatarsInRows]);
+    }, [icons, maxAvatarsInRow, shouldDisplayAvatarsInRows]);
 
-    if (!props.icons.length) {
+    if (!icons.length) {
         return null;
     }
 
-    if (props.icons.length === 1 && !props.shouldStackHorizontally) {
+    if (icons.length === 1 && !shouldStackHorizontally) {
         return (
             <UserDetailsTooltip
-                accountID={props.icons[0].id}
-                icon={props.icons[0]}
+                accountID={icons[0].id}
+                icon={icons[0]}
                 fallbackUserDetails={{
-                    displayName: props.icons[0].name,
-                    avatar: props.icons[0].avatar,
+                    displayName: icons[0].name,
+                    avatar: icons[0].source,
                 }}
             >
                 <View style={avatarContainerStyles}>
                     <Avatar
-                        source={props.icons[0].source}
-                        size={props.size}
+                        source={icons[0].source}
+                        size={size}
                         fill={themeColors.iconSuccessFill}
-                        name={props.icons[0].name}
-                        type={props.icons[0].type}
-                        fallbackIcon={props.icons[0].fallbackIcon}
+                        name={icons[0].name}
+                        type={icons[0].type}
+                        fallbackIcon={icons[0].fallbackIcon}
                     />
                 </View>
             </UserDetailsTooltip>
         );
     }
 
-    const oneAvatarSize = StyleUtils.getAvatarStyle(props.size);
-    const oneAvatarBorderWidth = StyleUtils.getAvatarBorderWidth(props.size).borderWidth;
+    const oneAvatarSize = StyleUtils.getAvatarStyle(size);
+    const oneAvatarBorderWidth = StyleUtils.getAvatarBorderWidth(size).borderWidth ?? 0;
     const overlapSize = oneAvatarSize.width / 3;
 
-    if (props.shouldStackHorizontally) {
+    if (shouldStackHorizontally) {
         // Height of one avatar + border space
         const height = oneAvatarSize.height + 2 * oneAvatarBorderWidth;
         avatarContainerStyles = StyleUtils.combineStyles([styles.alignItemsCenter, styles.flexRow, StyleUtils.getHeight(height)]);
@@ -159,36 +182,37 @@ function MultipleAvatars(props) {
 
     return (
         <>
-            {props.shouldStackHorizontally ? (
-                _.map(avatarRows, (avatars, rowIndex) => (
+            {shouldStackHorizontally ? (
+                avatarRows.map((avatars, rowIndex) => (
                     <View
                         style={avatarContainerStyles}
+                        /* eslint-disable-next-line react/no-array-index-key */
                         key={`avatarRow-${rowIndex}`}
                     >
-                        {_.map([...avatars].splice(0, props.maxAvatarsInRow), (icon, index) => (
+                        {[...avatars].splice(0, maxAvatarsInRow).map((icon, index) => (
                             <UserDetailsTooltip
-                                key={`stackedAvatars-${index}`}
+                                key={`stackedAvatars-${icon.id}`}
                                 accountID={icon.id}
                                 icon={icon}
                                 fallbackUserDetails={{
                                     displayName: icon.name,
-                                    avatar: icon.avatar,
+                                    avatar: icon.source,
                                 }}
                             >
-                                <View style={[StyleUtils.getHorizontalStackedAvatarStyle(index, overlapSize), StyleUtils.getAvatarBorderRadius(props.size, icon.type)]}>
+                                <View style={[StyleUtils.getHorizontalStackedAvatarStyle(index, overlapSize), StyleUtils.getAvatarBorderRadius(size, icon.type)]}>
                                     <Avatar
                                         iconAdditionalStyles={[
                                             StyleUtils.getHorizontalStackedAvatarBorderStyle({
-                                                isHovered: props.isHovered,
-                                                isPressed: props.isPressed,
-                                                isInReportAction: props.isInReportAction,
-                                                shouldUseCardBackground: props.shouldUseCardBackground,
+                                                isHovered,
+                                                isPressed,
+                                                isInReportAction,
+                                                shouldUseCardBackground,
                                             }),
-                                            StyleUtils.getAvatarBorderWidth(props.size),
+                                            StyleUtils.getAvatarBorderWidth(size),
                                         ]}
-                                        source={icon.source || props.fallbackIcon}
+                                        source={icon.source ?? fallbackIcon}
                                         fill={themeColors.iconSuccessFill}
-                                        size={props.size}
+                                        size={size}
                                         name={icon.name}
                                         type={icon.type}
                                         fallbackIcon={icon.fallbackIcon}
@@ -196,26 +220,26 @@ function MultipleAvatars(props) {
                                 </View>
                             </UserDetailsTooltip>
                         ))}
-                        {avatars.length > props.maxAvatarsInRow && (
+                        {avatars.length > maxAvatarsInRow && (
                             <Tooltip
                                 // We only want to cap tooltips to only 10 users or so since some reports have hundreds of users, causing performance to degrade.
-                                text={tooltipTexts.slice(avatarRows.length * props.maxAvatarsInRow - 1, avatarRows.length * props.maxAvatarsInRow + 9).join(', ')}
+                                text={tooltipTexts.slice(avatarRows.length * maxAvatarsInRow - 1, avatarRows.length * maxAvatarsInRow + 9).join(', ')}
                             >
                                 <View
                                     style={[
                                         styles.alignItemsCenter,
                                         styles.justifyContentCenter,
                                         StyleUtils.getHorizontalStackedAvatarBorderStyle({
-                                            isHovered: props.isHovered,
-                                            isPressed: props.isPressed,
-                                            isInReportAction: props.isInReportAction,
-                                            shouldUseCardBackground: props.shouldUseCardBackground,
+                                            isHovered,
+                                            isPressed,
+                                            isInReportAction,
+                                            shouldUseCardBackground,
                                         }),
 
                                         // Set overlay background color with RGBA value so that the text will not inherit opacity
                                         StyleUtils.getBackgroundColorWithOpacityStyle(themeColors.overlay, variables.overlayOpacity),
                                         StyleUtils.getHorizontalStackedOverlayAvatarStyle(oneAvatarSize, oneAvatarBorderWidth),
-                                        props.icons[3].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(props.size, props.icons[3].type) : {},
+                                        icons[3].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(size, icons[3].type) : {},
                                     ]}
                                 >
                                     <View
@@ -227,9 +251,9 @@ function MultipleAvatars(props) {
                                         ]}
                                     >
                                         <Text
-                                            style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(props.size), styles.userSelectNone]}
+                                            style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone]}
                                             dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
-                                        >{`+${avatars.length - props.maxAvatarsInRow}`}</Text>
+                                        >{`+${avatars.length - maxAvatarsInRow}`}</Text>
                                     </View>
                                 </View>
                             </Tooltip>
@@ -238,53 +262,47 @@ function MultipleAvatars(props) {
                 ))
             ) : (
                 <View style={avatarContainerStyles}>
-                    <View style={[singleAvatarStyle, props.icons[0].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(props.size, props.icons[0].type) : {}]}>
+                    <View style={[singleAvatarStyle, icons[0].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(size, icons[0].type) : {}]}>
                         <UserDetailsTooltip
-                            accountID={props.icons[0].id}
-                            icon={props.icons[0]}
+                            accountID={icons[0].id}
+                            icon={icons[0]}
                             fallbackUserDetails={{
-                                displayName: props.icons[0].name,
-                                avatar: props.icons[0].avatar,
+                                displayName: icons[0].name,
+                                avatar: icons[0].source,
                             }}
                         >
                             {/* View is necessary for tooltip to show for multiple avatars in LHN */}
                             <View>
                                 <Avatar
-                                    source={props.icons[0].source || props.fallbackIcon}
+                                    source={icons[0].source ?? fallbackIcon}
                                     fill={themeColors.iconSuccessFill}
                                     size={avatarSize}
                                     imageStyles={[singleAvatarStyle]}
-                                    name={props.icons[0].name}
-                                    type={props.icons[0].type}
-                                    fallbackIcon={props.icons[0].fallbackIcon}
+                                    name={icons[0].name}
+                                    type={icons[0].type}
+                                    fallbackIcon={icons[0].fallbackIcon}
                                 />
                             </View>
                         </UserDetailsTooltip>
-                        <View
-                            style={[
-                                secondAvatarStyles,
-                                ...props.secondAvatarStyle,
-                                props.icons[1].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(props.size, props.icons[1].type) : {},
-                            ]}
-                        >
-                            {props.icons.length === 2 ? (
+                        <View style={[secondAvatarStyles, secondAvatarStyle, icons[1].type === CONST.ICON_TYPE_WORKSPACE ? StyleUtils.getAvatarBorderRadius(size, icons[1].type) : {}]}>
+                            {icons.length === 2 ? (
                                 <UserDetailsTooltip
-                                    accountID={props.icons[1].id}
-                                    icon={props.icons[1]}
+                                    accountID={icons[1].id}
+                                    icon={icons[1]}
                                     fallbackUserDetails={{
-                                        displayName: props.icons[1].name,
-                                        avatar: props.icons[1].avatar,
+                                        displayName: icons[1].name,
+                                        avatar: icons[1].source,
                                     }}
                                 >
                                     <View>
                                         <Avatar
-                                            source={props.icons[1].source || props.fallbackIcon}
+                                            source={icons[1].source ?? fallbackIcon}
                                             fill={themeColors.iconSuccessFill}
                                             size={avatarSize}
                                             imageStyles={[singleAvatarStyle]}
-                                            name={props.icons[1].name}
-                                            type={props.icons[1].type}
-                                            fallbackIcon={props.icons[1].fallbackIcon}
+                                            name={icons[1].name}
+                                            type={icons[1].type}
+                                            fallbackIcon={icons[1].fallbackIcon}
                                         />
                                     </View>
                                 </UserDetailsTooltip>
@@ -292,10 +310,10 @@ function MultipleAvatars(props) {
                                 <Tooltip text={tooltipTexts.slice(1).join(', ')}>
                                     <View style={[singleAvatarStyle, styles.alignItemsCenter, styles.justifyContentCenter]}>
                                         <Text
-                                            style={(styles.userSelectNone, props.size === CONST.AVATAR_SIZE.SMALL ? styles.avatarInnerTextSmall : styles.avatarInnerText)}
+                                            style={[styles.userSelectNone, size === CONST.AVATAR_SIZE.SMALL ? styles.avatarInnerTextSmall : styles.avatarInnerText]}
                                             dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
                                         >
-                                            {`+${props.icons.length - 1}`}
+                                            {`+${icons.length - 1}`}
                                         </Text>
                                     </View>
                                 </Tooltip>
@@ -308,8 +326,6 @@ function MultipleAvatars(props) {
     );
 }
 
-MultipleAvatars.defaultProps = defaultProps;
-MultipleAvatars.propTypes = propTypes;
 MultipleAvatars.displayName = 'MultipleAvatars';
 
 export default memo(MultipleAvatars);
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index 19a607220e1c..c7c4428e19a3 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -15,7 +15,7 @@ const defaultProps = {
     shouldRender: true,
 };
 
-function Tooltip({shouldRender, children, ...props}) {
+function Tooltip({shouldRender = true, children, ...props}) {
     if (!shouldRender) {
         return children;
     }
diff --git a/src/components/UserDetailsTooltip/index.js b/src/components/UserDetailsTooltip/index.js
index ea5cd4337071..6e256ac9ba9e 100644
--- a/src/components/UserDetailsTooltip/index.js
+++ b/src/components/UserDetailsTooltip/index.js
@@ -15,7 +15,7 @@ const defaultProps = {
     shouldRender: true,
 };
 
-function UserDetailsTooltip({shouldRender, children, ...props}) {
+function UserDetailsTooltip({shouldRender = true, children, ...props}) {
     if (!shouldRender) {
         return children;
     }
diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts
index f7883609f625..1a5ced6c9f85 100644
--- a/src/libs/UserUtils.ts
+++ b/src/libs/UserUtils.ts
@@ -8,6 +8,8 @@ import hashCode from './hashCode';
 
 type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24;
 
+type AvatarSource = React.FC<SvgProps> | string;
+
 type LoginListIndicator = ValueOf<typeof CONST.BRICK_ROAD_INDICATOR_STATUS> | '';
 
 /**
@@ -202,3 +204,4 @@ export {
     getFullSizeAvatar,
     generateAccountID,
 };
+export type {AvatarSource};
diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts
index 42b7860ee263..b1116b372c2f 100644
--- a/src/styles/StyleUtils.ts
+++ b/src/styles/StyleUtils.ts
@@ -17,6 +17,12 @@ import variables from './variables';
 
 type AllStyles = ViewStyle | TextStyle | ImageStyle;
 type ParsableStyle = StyleProp<ViewStyle> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>);
+type AvatarStyle = {
+    width: number;
+    height: number;
+    borderRadius: number;
+    backgroundColor: string;
+};
 
 type ColorValue = ValueOf<typeof colors>;
 type AvatarSizeName = ValueOf<typeof CONST.AVATAR_SIZE>;
@@ -210,7 +216,7 @@ function getAvatarWidthStyle(size: AvatarSizeName): ViewStyle {
 /**
  * Return the style from an avatar size constant
  */
-function getAvatarStyle(size: AvatarSizeName): ViewStyle {
+function getAvatarStyle(size: AvatarSizeName): AvatarStyle {
     const avatarSize = getAvatarSize(size);
     return {
         height: avatarSize,
@@ -241,7 +247,7 @@ function getAvatarBorderWidth(size: AvatarSizeName): ViewStyle {
 /**
  * Return the border radius for an avatar
  */
-function getAvatarBorderRadius(size: AvatarSizeName, type: string): ViewStyle {
+function getAvatarBorderRadius(size: AvatarSizeName, type?: string): ViewStyle {
     if (type === CONST.ICON_TYPE_WORKSPACE) {
         return {borderRadius: avatarBorderSizes[size]};
     }
@@ -1286,8 +1292,8 @@ function getAmountFontSizeAndLineHeight(baseFontSize: number, baseLineHeight: nu
 /**
  * Returns container styles for showing the icons in MultipleAvatars/SubscriptAvatar
  */
-function getContainerStyles(size: string, isInReportAction = false): Array<ViewStyle | CSSProperties> {
-    let containerStyles: Array<ViewStyle | CSSProperties>;
+function getContainerStyles(size: string, isInReportAction = false): ViewStyle[] {
+    let containerStyles: ViewStyle[];
 
     switch (size) {
         case CONST.AVATAR_SIZE.SMALL:

From ab92c85b94f09b58e565ac66b15528b53affbdaf Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 8 Nov 2023 12:26:04 +0100
Subject: [PATCH 2/6] Update OnyxCommon Icon type

---
 src/components/MultipleAvatars.tsx | 20 ++------------------
 src/types/onyx/OnyxCommon.ts       | 19 +++++++++++++++----
 2 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx
index 00c591e3a580..e3d871e0f888 100644
--- a/src/components/MultipleAvatars.tsx
+++ b/src/components/MultipleAvatars.tsx
@@ -7,31 +7,15 @@ import * as StyleUtils from '@styles/StyleUtils';
 import themeColors from '@styles/themes/default';
 import variables from '@styles/variables';
 import CONST from '@src/CONST';
+import type {Icon} from '@src/types/onyx/OnyxCommon';
 import Avatar from './Avatar';
 import Text from './Text';
 import Tooltip from './Tooltip';
 import UserDetailsTooltip from './UserDetailsTooltip';
 
-type AvatarType = {
-    /** Avatar source to display */
-    source?: AvatarSource;
-
-    /** Denotes whether it is an avatar or a workspace avatar */
-    type?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
-
-    /** Owner of the avatar. If user, displayName. If workspace, policy name */
-    name?: string;
-
-    /** Avatar id */
-    id?: number | string;
-
-    /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
-    fallbackIcon?: AvatarSource;
-};
-
 type MultipleAvatarsProps = {
     /** Array of avatar URLs or icons */
-    icons: AvatarType[];
+    icons: Icon[];
 
     /** Set the size of avatars */
     size: ValueOf<typeof CONST.AVATAR_SIZE>;
diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts
index ef2944d6af82..4d376b8b7da8 100644
--- a/src/types/onyx/OnyxCommon.ts
+++ b/src/types/onyx/OnyxCommon.ts
@@ -1,5 +1,5 @@
-import * as React from 'react';
 import {ValueOf} from 'type-fest';
+import {AvatarSource} from '@libs/UserUtils';
 import CONST from '@src/CONST';
 
 type PendingAction = ValueOf<typeof CONST.RED_BRICK_ROAD_PENDING_ACTION>;
@@ -11,9 +11,20 @@ type ErrorFields<TKey extends string = string> = Record<TKey, Errors | null | un
 type Errors = Record<string, string>;
 
 type Icon = {
-    source: React.ReactNode | string;
-    type: 'avatar' | 'workspace';
-    name: string;
+    /** Avatar source to display */
+    source?: AvatarSource;
+
+    /** Denotes whether it is an avatar or a workspace avatar */
+    type?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
+
+    /** Owner of the avatar. If user, displayName. If workspace, policy name */
+    name?: string;
+
+    /** Avatar id */
+    id?: number | string;
+
+    /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
+    fallbackIcon?: AvatarSource;
 };
 
 export type {Icon, PendingAction, PendingFields, ErrorFields, Errors};

From cf6410f9128a085ef065fd3441cd352885bb799a Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 8 Nov 2023 12:39:35 +0100
Subject: [PATCH 3/6] Add useMemo for tooltipTexts

---
 src/components/MultipleAvatars.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx
index e3d871e0f888..a86d4946856e 100644
--- a/src/components/MultipleAvatars.tsx
+++ b/src/components/MultipleAvatars.tsx
@@ -96,7 +96,7 @@ function MultipleAvatars({
     let avatarContainerStyles = StyleUtils.getContainerStyles(size, isInReportAction);
     const {singleAvatarStyle, secondAvatarStyles} = useMemo(() => avatarSizeToStylesMap[size as AvatarSizeToStyles] ?? avatarSizeToStylesMap.default, [size]);
 
-    const tooltipTexts = shouldShowTooltip ? icons.map((icon) => icon.name) : [''];
+    const tooltipTexts = useMemo(() => (shouldShowTooltip ? icons.map((icon) => icon.name) : ['']), [shouldShowTooltip, icons]);
     const avatarSize = useMemo(() => {
         if (isFocusMode) {
             return CONST.AVATAR_SIZE.MID_SUBSCRIPT;

From bc3181ae12a98fd29add7af9e51847c6cc18a08a Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 8 Nov 2023 18:06:05 +0100
Subject: [PATCH 4/6] Make size and secondAvatarStyle to be optional

---
 src/components/MultipleAvatars.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx
index a86d4946856e..4101fd381a3f 100644
--- a/src/components/MultipleAvatars.tsx
+++ b/src/components/MultipleAvatars.tsx
@@ -18,10 +18,10 @@ type MultipleAvatarsProps = {
     icons: Icon[];
 
     /** Set the size of avatars */
-    size: ValueOf<typeof CONST.AVATAR_SIZE>;
+    size?: ValueOf<typeof CONST.AVATAR_SIZE>;
 
     /** Style for Second Avatar */
-    secondAvatarStyle: StyleProp<ViewStyle>;
+    secondAvatarStyle?: StyleProp<ViewStyle>;
 
     /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
     fallbackIcon?: AvatarSource;

From 22f237f122150cfa41698d19835c044e76460ea8 Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 8 Nov 2023 18:50:06 +0100
Subject: [PATCH 5/6] Remove unused avatar props

---
 src/components/MultipleAvatars.tsx | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx
index 4101fd381a3f..e867de7ddb97 100644
--- a/src/components/MultipleAvatars.tsx
+++ b/src/components/MultipleAvatars.tsx
@@ -137,7 +137,6 @@ function MultipleAvatars({
                 icon={icons[0]}
                 fallbackUserDetails={{
                     displayName: icons[0].name,
-                    avatar: icons[0].source,
                 }}
             >
                 <View style={avatarContainerStyles}>
@@ -180,7 +179,6 @@ function MultipleAvatars({
                                 icon={icon}
                                 fallbackUserDetails={{
                                     displayName: icon.name,
-                                    avatar: icon.source,
                                 }}
                             >
                                 <View style={[StyleUtils.getHorizontalStackedAvatarStyle(index, overlapSize), StyleUtils.getAvatarBorderRadius(size, icon.type)]}>
@@ -252,7 +250,6 @@ function MultipleAvatars({
                             icon={icons[0]}
                             fallbackUserDetails={{
                                 displayName: icons[0].name,
-                                avatar: icons[0].source,
                             }}
                         >
                             {/* View is necessary for tooltip to show for multiple avatars in LHN */}
@@ -275,7 +272,6 @@ function MultipleAvatars({
                                     icon={icons[1]}
                                     fallbackUserDetails={{
                                         displayName: icons[1].name,
-                                        avatar: icons[1].source,
                                     }}
                                 >
                                     <View>

From 60f26d3968f16d800873adb53fefd1f46f1da8d0 Mon Sep 17 00:00:00 2001
From: Viktoryia Kliushun <vikstash@gmail.com>
Date: Wed, 15 Nov 2023 11:26:16 +0100
Subject: [PATCH 6/6] Update icon type

---
 src/types/onyx/OnyxCommon.ts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts
index 4d376b8b7da8..ac69baed3ef1 100644
--- a/src/types/onyx/OnyxCommon.ts
+++ b/src/types/onyx/OnyxCommon.ts
@@ -12,16 +12,16 @@ type Errors = Record<string, string>;
 
 type Icon = {
     /** Avatar source to display */
-    source?: AvatarSource;
+    source: AvatarSource;
 
     /** Denotes whether it is an avatar or a workspace avatar */
-    type?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
+    type: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
 
     /** Owner of the avatar. If user, displayName. If workspace, policy name */
-    name?: string;
+    name: string;
 
     /** Avatar id */
-    id?: number | string;
+    id: number | string;
 
     /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
     fallbackIcon?: AvatarSource;
