// Copyright 2018-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import React, { FunctionComponent, ReactNode, useEffect, useState, } from 'react'; import classNames from 'classnames'; import { Spinner } from './Spinner'; import { getInitials } from '../util/getInitials'; import { LocalizerType } from '../types/Util'; import { ColorType } from '../types/Colors'; import * as log from '../logging/log'; export enum AvatarSize { TWENTY_EIGHT = 28, THIRTY_TWO = 32, FIFTY_TWO = 52, EIGHTY = 80, NINETY_SIX = 96, ONE_HUNDRED_TWELVE = 112, } export type Props = { avatarPath?: string; color?: ColorType; loading?: boolean; conversationType: 'group' | 'direct'; noteToSelf?: boolean; title: string; name?: string; phoneNumber?: string; profileName?: string; size: AvatarSize; onClick?: () => unknown; // Matches Popper's RefHandler type innerRef?: React.Ref; i18n: LocalizerType; } & Pick, 'className'>; export const Avatar: FunctionComponent = ({ avatarPath, className, color, conversationType, i18n, innerRef, loading, noteToSelf, onClick, size, title, }) => { const [imageBroken, setImageBroken] = useState(false); useEffect(() => { setImageBroken(false); }, [avatarPath]); const initials = getInitials(title); const hasImage = !noteToSelf && avatarPath && !imageBroken; const shouldUseInitials = !hasImage && conversationType === 'direct' && Boolean(initials); let contents: ReactNode; if (loading) { const svgSize = size < 40 ? 'small' : 'normal'; contents = (
); } else if (hasImage) { contents = ( { log.warn('Avatar: Image failed to load; failing over to placeholder'); setImageBroken(true); }} alt={i18n('contactAvatarAlt', [title])} src={avatarPath} /> ); } else if (noteToSelf) { contents = (
); } else if (shouldUseInitials) { contents = (
{initials}
); } else { contents = (
); } if (onClick) { contents = ( ); } return (
{contents}
); };