From cb0a26941bf9b11b900fa9f61a207b4a8e37a19a Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 16 Oct 2024 14:58:34 +0200 Subject: [PATCH] fix: wrap the UserAvatar component in forwardRef (#8461) This fixes another one of the warnings we have in our tests and is probably a sane change to make anyway. --- .../common/AvatarGroup/AvatarGroup.tsx | 24 +++- .../AvatarGroupFromOwners.tsx | 8 +- .../common/UserAvatar/UserAvatar.tsx | 109 +++++++++--------- 3 files changed, 77 insertions(+), 64 deletions(-) diff --git a/frontend/src/component/common/AvatarGroup/AvatarGroup.tsx b/frontend/src/component/common/AvatarGroup/AvatarGroup.tsx index ec7ee2d553..8b63b4874d 100644 --- a/frontend/src/component/common/AvatarGroup/AvatarGroup.tsx +++ b/frontend/src/component/common/AvatarGroup/AvatarGroup.tsx @@ -1,8 +1,16 @@ import { styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import type { IGroupUser } from 'interfaces/group'; -import { useMemo } from 'react'; -import { UserAvatar } from 'component/common/UserAvatar/UserAvatar'; // usage +import { + type ForwardRefExoticComponent, + type FunctionComponent, + type RefAttributes, + useMemo, +} from 'react'; +import { + type IUserAvatarProps, + UserAvatar, +} from 'component/common/UserAvatar/UserAvatar'; import { objectId } from 'utils/objectId'; import millify from 'millify'; @@ -14,6 +22,12 @@ const StyledAvatars = styled('div')(({ theme }) => ({ justifyContent: 'start', })); +export type AvatarComponentType = + | FunctionComponent + | ForwardRefExoticComponent< + IUserAvatarProps & RefAttributes + >; + export const AvatarComponent = styled(UserAvatar)(({ theme }) => ({ outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`, margin: 0, @@ -21,7 +35,7 @@ export const AvatarComponent = styled(UserAvatar)(({ theme }) => ({ '&:hover': { outlineColor: theme.palette.primary.main, }, -})); +})) as AvatarComponentType; type User = { name: string; @@ -32,7 +46,7 @@ type User = { type AvatarGroupProps = { users: User[]; avatarLimit?: number; - AvatarComponent?: typeof UserAvatar; + AvatarComponent?: AvatarComponentType; className?: string; }; @@ -44,7 +58,7 @@ export const AvatarGroup = ({ ...props }: AvatarGroupProps) => ( ); type AvatarGroupInnerProps = Omit & { - AvatarComponent: typeof UserAvatar; + AvatarComponent: AvatarComponentType; }; const MAX_OVERFLOW_DISPLAY_NUMBER = 99; diff --git a/frontend/src/component/common/AvatarGroupFromOwners/AvatarGroupFromOwners.tsx b/frontend/src/component/common/AvatarGroupFromOwners/AvatarGroupFromOwners.tsx index 258def196f..6619e715cc 100644 --- a/frontend/src/component/common/AvatarGroupFromOwners/AvatarGroupFromOwners.tsx +++ b/frontend/src/component/common/AvatarGroupFromOwners/AvatarGroupFromOwners.tsx @@ -1,12 +1,14 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import type { ProjectSchemaOwners } from 'openapi'; -import type { UserAvatar } from '../UserAvatar/UserAvatar'; -import { AvatarGroup } from '../AvatarGroup/AvatarGroup'; +import { + type AvatarComponentType, + AvatarGroup, +} from '../AvatarGroup/AvatarGroup'; type Props = { users: ProjectSchemaOwners; avatarLimit?: number; - AvatarComponent?: typeof UserAvatar; + AvatarComponent?: AvatarComponentType; className?: string; }; export const AvatarGroupFromOwners: React.FC = ({ users, ...props }) => { diff --git a/frontend/src/component/common/UserAvatar/UserAvatar.tsx b/frontend/src/component/common/UserAvatar/UserAvatar.tsx index 6c329c2ddd..be3a37c6d0 100644 --- a/frontend/src/component/common/UserAvatar/UserAvatar.tsx +++ b/frontend/src/component/common/UserAvatar/UserAvatar.tsx @@ -6,7 +6,7 @@ import { type Theme, } from '@mui/material'; import type { IUser } from 'interfaces/user'; -import type { FC } from 'react'; +import { forwardRef } from 'react'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { HtmlTooltip } from '../HtmlTooltip/HtmlTooltip'; const StyledAvatar = styled(Avatar)(({ theme }) => ({ @@ -60,63 +60,60 @@ const TooltipMainContent = styled('div')(({ theme }) => ({ fontSize: theme.typography.body1.fontSize, })); -export const UserAvatar: FC = ({ - user, - src, - className, - sx, - children, - disableTooltip, - ...props -}) => { - let fallback: string | undefined; - if (!children && user) { - fallback = user?.name || user?.email || user?.username; - if (fallback?.includes(' ')) { - fallback = `${fallback.split(' ')[0][0]}${ - fallback.split(' ')[1][0] - }`.toUpperCase(); - } else if (fallback) { - fallback = fallback[0].toUpperCase(); +export const UserAvatar = forwardRef( + ({ user, src, className, sx, children, disableTooltip, ...props }, ref) => { + let fallback: string | undefined; + if (!children && user) { + fallback = user?.name || user?.email || user?.username; + if (fallback?.includes(' ')) { + fallback = `${fallback.split(' ')[0][0]}${ + fallback.split(' ')[1][0] + }`.toUpperCase(); + } else if (fallback) { + fallback = fallback[0].toUpperCase(); + } } - } - const Avatar = ( - - - - ); - - const tooltip = disableTooltip ? undefined : tooltipContent(user); - if (tooltip) { - return ( - - - {tooltip.secondary} - - {tooltip.main} - - } + const Avatar = ( + - {Avatar} - + + ); - } - return Avatar; -}; + const tooltip = disableTooltip ? undefined : tooltipContent(user); + if (tooltip) { + return ( + + + {tooltip.secondary} + + + {tooltip.main} + + + } + > + {Avatar} + + ); + } + + return Avatar; + }, +);