Skip to content

Commit

Permalink
Merge pull request Expensify#30328 from fabioh8010/ts/component/Avata…
Browse files Browse the repository at this point in the history
…rWithIndicator

[TS migration] Migrate 'AvatarWithIndicator.js' component to TypeScript
  • Loading branch information
Beamanator authored Dec 1, 2023
2 parents 2e8de3f + fef6485 commit 27fd4e2
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import * as UserUtils from '@libs/UserUtils';
Expand All @@ -9,38 +8,33 @@ import * as Expensicons from './Icon/Expensicons';
import Indicator from './Indicator';
import Tooltip from './Tooltip';

const propTypes = {
type AvatarWithIndicatorProps = {
/** URL for the avatar */
source: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
source: UserUtils.AvatarSource;

/** To show a tooltip on hover */
tooltipText: PropTypes.string,
tooltipText?: string;

/** 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?: UserUtils.AvatarSource;

/** Indicates whether the avatar is loaded or not */
isLoading: PropTypes.bool,
isLoading?: boolean;
};

const defaultProps = {
tooltipText: '',
fallbackIcon: Expensicons.FallbackAvatar,
isLoading: true,
};

function AvatarWithIndicator(props) {
function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) {
const styles = useThemeStyles();

return (
<Tooltip text={props.tooltipText}>
<Tooltip text={tooltipText}>
<View style={[styles.sidebarAvatar]}>
{props.isLoading ? (
{isLoading ? (
<AvatarSkeleton />
) : (
<>
<Avatar
source={UserUtils.getSmallSizeAvatar(props.source)}
fallbackIcon={props.fallbackIcon}
source={UserUtils.getSmallSizeAvatar(source)}
fallbackIcon={fallbackIcon}
/>
<Indicator />
</>
Expand All @@ -50,8 +44,6 @@ function AvatarWithIndicator(props) {
);
}

AvatarWithIndicator.defaultProps = defaultProps;
AvatarWithIndicator.propTypes = propTypes;
AvatarWithIndicator.displayName = 'AvatarWithIndicator';

export default AvatarWithIndicator;
32 changes: 16 additions & 16 deletions src/libs/UserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,37 +105,37 @@ function getDefaultAvatarURL(accountID: string | number = '', isNewDot = false):

/**
* Given a user's avatar path, returns true if user doesn't have an avatar or if URL points to a default avatar
* @param [avatarURL] - the avatar source from user's personalDetails
* @param avatarSource - the avatar source from user's personalDetails
*/
function isDefaultAvatar(avatarURL?: string | React.FC<SvgProps>): boolean {
if (typeof avatarURL === 'string') {
if (avatarURL.includes('images/avatars/avatar_') || avatarURL.includes('images/avatars/default-avatar_') || avatarURL.includes('images/avatars/user/default')) {
function isDefaultAvatar(avatarSource?: AvatarSource): boolean {
if (typeof avatarSource === 'string') {
if (avatarSource.includes('images/avatars/avatar_') || avatarSource.includes('images/avatars/default-avatar_') || avatarSource.includes('images/avatars/user/default')) {
return true;
}

// We use a hardcoded "default" Concierge avatar
if (avatarURL === CONST.CONCIERGE_ICON_URL_2021 || avatarURL === CONST.CONCIERGE_ICON_URL) {
if (avatarSource === CONST.CONCIERGE_ICON_URL_2021 || avatarSource === CONST.CONCIERGE_ICON_URL) {
return true;
}
}

if (!avatarURL) {
// If null URL, we should also use a default avatar
if (!avatarSource) {
// If null source, we should also use a default avatar
return true;
}

return false;
}

/**
* Provided a source URL, if source is a default avatar, return the associated SVG.
* Otherwise, return the URL pointing to a user-uploaded avatar.
* Provided an avatar source, if source is a default avatar, return the associated SVG.
* Otherwise, return the URL or SVG pointing to the user-uploaded avatar.
*
* @param avatarURL - the avatar source from user's personalDetails
* @param avatarSource - the avatar source from user's personalDetails
* @param accountID - the accountID of the user
*/
function getAvatar(avatarURL: AvatarSource, accountID: number): AvatarSource {
return isDefaultAvatar(avatarURL) ? getDefaultAvatar(accountID) : avatarURL;
function getAvatar(avatarSource: AvatarSource, accountID?: number): AvatarSource {
return isDefaultAvatar(avatarSource) ? getDefaultAvatar(accountID) : avatarSource;
}

/**
Expand All @@ -153,8 +153,8 @@ function getAvatarUrl(avatarURL: string, accountID: number): string {
* Avatars uploaded by users will have a _128 appended so that the asset server returns a small version.
* This removes that part of the URL so the full version of the image can load.
*/
function getFullSizeAvatar(avatarURL: string, accountID: number): AvatarSource {
const source = getAvatar(avatarURL, accountID);
function getFullSizeAvatar(avatarSource: AvatarSource, accountID: number): AvatarSource {
const source = getAvatar(avatarSource, accountID);
if (typeof source !== 'string') {
return source;
}
Expand All @@ -165,8 +165,8 @@ function getFullSizeAvatar(avatarURL: string, accountID: number): AvatarSource {
* Small sized avatars end with _128.<file-type>. This adds the _128 at the end of the
* source URL (before the file type) if it doesn't exist there already.
*/
function getSmallSizeAvatar(avatarURL: string, accountID: number): AvatarSource {
const source = getAvatar(avatarURL, accountID);
function getSmallSizeAvatar(avatarSource: AvatarSource, accountID?: number): AvatarSource {
const source = getAvatar(avatarSource, accountID);
if (typeof source !== 'string') {
return source;
}
Expand Down
6 changes: 3 additions & 3 deletions src/types/onyx/ReportAction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {SvgProps} from 'react-native-svg';
import {ValueOf} from 'type-fest';
import {AvatarSource} from '@libs/UserUtils';
import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
import OriginalMessage, {Decision, Reaction} from './OriginalMessage';
Expand Down Expand Up @@ -85,7 +85,7 @@ type ReportActionBase = {
/** accountIDs of the people to which the whisper was sent to (if any). Returns empty array if it is not a whisper */
whisperedToAccountIDs?: number[];

avatar?: string | React.FC<SvgProps>;
avatar?: AvatarSource;

automatic?: boolean;

Expand Down Expand Up @@ -145,4 +145,4 @@ type ReportAction = ReportActionBase & OriginalMessage;
type ReportActions = Record<string, ReportAction>;

export default ReportAction;
export type {ReportActions, Message};
export type {Message, ReportActions};

0 comments on commit 27fd4e2

Please sign in to comment.