import React, { useState } from 'react'; import classNames from 'classnames'; import { useEncryptedFileFetch } from '../hooks/useEncryptedFileFetch'; import _ from 'underscore'; import { useAvatarPath, useConversationUsername, useIsClosedGroup, } from '../hooks/useParamSelector'; import { AvatarPlaceHolder } from './AvatarPlaceHolder/AvatarPlaceHolder'; import { ClosedGroupAvatar } from './AvatarPlaceHolder/ClosedGroupAvatar'; import { useDisableDrag } from '../hooks/useDisableDrag'; export enum AvatarSize { XS = 28, S = 36, M = 48, L = 64, XL = 80, HUGE = 300, } type Props = { forcedAvatarPath?: string | null; forcedName?: string; pubkey: string; size: AvatarSize; base64Data?: string; // if this is not empty, it will be used to render the avatar with base64 encoded data onAvatarClick?: () => void; dataTestId?: string; }; const Identicon = (props: Props) => { const { size, forcedName, pubkey } = props; const displayName = useConversationUsername(pubkey); const userName = forcedName || displayName || '0'; return ; }; const NoImage = ( props: Pick & { isClosedGroup: boolean; } ) => { const { forcedName, size, pubkey, isClosedGroup } = props; // if no image but we have conversations set for the group, renders group members avatars if (pubkey && isClosedGroup) { return ( ); } return ; }; const AvatarImage = (props: { avatarPath?: string; base64Data?: string; name?: string; // display name, profileName or pubkey, whatever is set first imageBroken: boolean; handleImageError: () => any; }) => { const { avatarPath, base64Data, name, imageBroken, handleImageError } = props; const disableDrag = useDisableDrag(); if ((!avatarPath && !base64Data) || imageBroken) { return null; } const dataToDisplay = base64Data ? `data:image/jpeg;base64,${base64Data}` : avatarPath; return ( {window.i18n('contactAvatarAlt', ); }; const AvatarInner = (props: Props) => { const { base64Data, size, pubkey, forcedAvatarPath, forcedName, dataTestId } = props; const [imageBroken, setImageBroken] = useState(false); const isClosedGroupAvatar = useIsClosedGroup(pubkey); const avatarPath = useAvatarPath(pubkey); const name = useConversationUsername(pubkey); // contentType is not important const { urlToLoad } = useEncryptedFileFetch(forcedAvatarPath || avatarPath || '', '', true); const handleImageError = () => { window.log.warn( 'Avatar: Image failed to load; failing over to placeholder', urlToLoad, forcedAvatarPath || avatarPath ); setImageBroken(true); }; const hasImage = (base64Data || urlToLoad) && !imageBroken && !isClosedGroupAvatar; const isClickable = !!props.onAvatarClick; return (
{ e.stopPropagation(); props.onAvatarClick?.(); }} role="button" data-testid={dataTestId} > {hasImage ? ( ) : ( )}
); }; export const Avatar = React.memo(AvatarInner, _.isEqual);