Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 27252 Profile pic gets removed in offline mode #27757

Merged
merged 6 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ function AttachmentModal(props) {
file={file}
onToggleKeyboard={updateConfirmButtonVisibility}
isWorkspaceAvatar={props.isWorkspaceAvatar}
fallbackSource={props.fallbackSource}
/>
)
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ const propTypes = {
...withLocalizePropTypes,
};

function AttachmentViewImage({source, file, isAuthTokenRequired, loadComplete, onPress, isImage, onScaleChanged, translate}) {
function AttachmentViewImage({source, file, isAuthTokenRequired, loadComplete, onPress, isImage, onScaleChanged, translate, onError}) {
const children = (
<ImageView
onScaleChanged={onScaleChanged}
url={source}
fileName={file.name}
isAuthTokenRequired={isImage && isAuthTokenRequired}
onError={onError}
/>
);
return onPress ? (
Expand Down
11 changes: 10 additions & 1 deletion src/components/Attachments/AttachmentView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import AttachmentViewPdf from './AttachmentViewPdf';
import addEncryptedAuthTokenToURL from '../../../libs/addEncryptedAuthTokenToURL';
import * as StyleUtils from '../../../styles/StyleUtils';
import {attachmentViewPropTypes, attachmentViewDefaultProps} from './propTypes';
import useNetwork from '../../../hooks/useNetwork';

const propTypes = {
...attachmentViewPropTypes,
Expand Down Expand Up @@ -62,9 +63,14 @@ function AttachmentView({
translate,
isFocused,
isWorkspaceAvatar,
fallbackSource,
}) {
const [loadComplete, setLoadComplete] = useState(false);

const [imageError, setImageError] = useState(false);

useNetwork({onReconnect: () => setImageError(false)});

// Handles case where source is a component (ex: SVG)
if (_.isFunction(source)) {
let iconFillColor = '';
Expand Down Expand Up @@ -113,7 +119,7 @@ function AttachmentView({
if (isImage || (file && Str.isImage(file.name))) {
return (
<AttachmentViewImage
source={source}
source={imageError ? fallbackSource : source}
file={file}
isAuthTokenRequired={isAuthTokenRequired}
isUsedInCarousel={isUsedInCarousel}
Expand All @@ -122,6 +128,9 @@ function AttachmentView({
isImage={isImage}
onPress={onPress}
onScaleChanged={onScaleChanged}
onError={() => {
setImageError(true);
}}
/>
);
}
Expand Down
14 changes: 9 additions & 5 deletions src/components/Avatar.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useState} from 'react';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
Expand Down Expand Up @@ -40,7 +40,7 @@ const propTypes = {
/** A fallback avatar icon to display when there is an error on loading avatar from remote URL.
* If the avatar is type === workspace, this fallback icon will be ignored and decided based on the name prop.
*/
fallbackIcon: PropTypes.func,
fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),

/** Denotes whether it is an avatar or a workspace avatar */
type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]),
Expand All @@ -66,6 +66,10 @@ function Avatar(props) {

useNetwork({onReconnect: () => setImageError(false)});

useEffect(() => {
setImageError(false);
}, [props.source]);

if (!props.source) {
return null;
}
Expand All @@ -81,14 +85,14 @@ function Avatar(props) {
const iconStyle = props.imageStyles && props.imageStyles.length ? [StyleUtils.getAvatarStyle(props.size), styles.bgTransparent, ...props.imageStyles] : undefined;

const iconFillColor = isWorkspace ? StyleUtils.getDefaultWorkspaceAvatarColor(props.name).fill : props.fill;
const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(props.name) : props.fallbackIcon;
const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(props.name) : props.fallbackIcon || Expensicons.FallbackAvatar;

return (
<View
pointerEvents="none"
style={props.containerStyles}
>
{_.isFunction(props.source) || imageError ? (
{_.isFunction(props.source) || (imageError && _.isFunction(fallbackAvatar)) ? (
<View style={iconStyle}>
<Icon
src={imageError ? fallbackAvatar : props.source}
Expand All @@ -106,7 +110,7 @@ function Avatar(props) {
) : (
<View style={[iconStyle, StyleUtils.getAvatarBorderStyle(props.size, props.type), ...props.iconAdditionalStyles]}>
<Image
source={{uri: props.source}}
source={{uri: imageError ? fallbackAvatar : props.source}}
style={imageStyle}
onError={() => setImageError(true)}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/components/AvatarWithImagePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const propTypes = {
size: PropTypes.oneOf([CONST.AVATAR_SIZE.LARGE, CONST.AVATAR_SIZE.DEFAULT]),

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,
fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),

/** Denotes whether it is an avatar or a workspace avatar */
type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]),
Expand Down Expand Up @@ -296,6 +296,7 @@ class AvatarWithImagePicker extends React.Component {
headerTitle={this.props.headerTitle}
source={this.props.previewSource}
originalFileName={this.props.originalFileName}
fallbackSource={this.props.fallbackIcon}
>
{({show}) => (
<AttachmentPicker type={CONST.ATTACHMENT_PICKER_TYPE.IMAGE}>
Expand Down
10 changes: 9 additions & 1 deletion src/components/AvatarWithIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,32 @@ import styles from '../styles/styles';
import Tooltip from './Tooltip';
import * as UserUtils from '../libs/UserUtils';
import Indicator from './Indicator';
import * as Expensicons from './Icon/Expensicons';

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

/** To show a tooltip on hover */
tooltipText: PropTypes.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]),
};

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

function AvatarWithIndicator(props) {
return (
<Tooltip text={props.tooltipText}>
<View style={[styles.sidebarAvatar]}>
<Avatar source={UserUtils.getSmallSizeAvatar(props.source)} />
<Avatar
source={UserUtils.getSmallSizeAvatar(props.source)}
fallbackIcon={props.fallbackIcon}
/>
<Indicator />
</View>
</Tooltip>
Expand Down
7 changes: 6 additions & 1 deletion src/components/ImageView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ const propTypes = {

/** image file name */
fileName: PropTypes.string.isRequired,

onError: PropTypes.func,
};

const defaultProps = {
isAuthTokenRequired: false,
onError: () => {},
};

function ImageView({isAuthTokenRequired, url, fileName}) {
function ImageView({isAuthTokenRequired, url, fileName, onError}) {
const [isLoading, setIsLoading] = useState(true);
const [containerHeight, setContainerHeight] = useState(0);
const [containerWidth, setContainerWidth] = useState(0);
Expand Down Expand Up @@ -238,6 +241,7 @@ function ImageView({isAuthTokenRequired, url, fileName}) {
resizeMode={zoomScale > 1 ? Image.resizeMode.center : Image.resizeMode.contain}
onLoadStart={imageLoadingStart}
onLoad={imageLoad}
onError={onError}
/>
{(isLoading || zoomScale === 0) && <FullscreenLoadingIndicator style={[styles.opacity1, styles.bgTransparent]} />}
</View>
Expand Down Expand Up @@ -268,6 +272,7 @@ function ImageView({isAuthTokenRequired, url, fileName}) {
resizeMode={Image.resizeMode.contain}
onLoadStart={imageLoadingStart}
onLoad={imageLoad}
onError={onError}
/>
</PressableWithoutFeedback>

Expand Down
1 change: 1 addition & 0 deletions src/components/LHNOptionsList/OptionRowLHNData.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ const personalDetailsSelector = (personalDetails) =>
firstName: personalData.firstName,
status: personalData.status,
avatar: UserUtils.getAvatar(personalData.avatar, personalData.accountID),
fallbackIcon: personalData.fallbackIcon,
};
return finalPersonalDetails;
},
Expand Down
1 change: 1 addition & 0 deletions src/components/MentionSuggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ function MentionSuggestions(props) {
name={item.icons[0].name}
type={item.icons[0].type}
fill={themeColors.success}
fallbackIcon={item.icons[0].fallbackIcon}
/>
</View>
<Text
Expand Down
6 changes: 5 additions & 1 deletion src/components/MultipleAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const propTypes = {
secondAvatarStyle: PropTypes.arrayOf(PropTypes.object),

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,
fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),

/** Prop to identify if we should load avatars vertically instead of diagonally */
shouldStackHorizontally: PropTypes.bool,
Expand Down Expand Up @@ -134,6 +134,7 @@ function MultipleAvatars(props) {
fill={themeColors.iconSuccessFill}
name={props.icons[0].name}
type={props.icons[0].type}
fallbackIcon={props.icons[0].fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand Down Expand Up @@ -184,6 +185,7 @@ function MultipleAvatars(props) {
size={props.size}
name={icon.name}
type={icon.type}
fallbackIcon={icon.fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand Down Expand Up @@ -249,6 +251,7 @@ function MultipleAvatars(props) {
imageStyles={[singleAvatarStyle]}
name={props.icons[0].name}
type={props.icons[0].type}
fallbackIcon={props.icons[0].fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand All @@ -270,6 +273,7 @@ function MultipleAvatars(props) {
imageStyles={[singleAvatarStyle]}
name={props.icons[1].name}
type={props.icons[1].type}
fallbackIcon={props.icons[1].fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand Down
2 changes: 2 additions & 0 deletions src/components/RoomHeaderAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function RoomHeaderAvatars(props) {
size={CONST.AVATAR_SIZE.LARGE}
name={props.icons[0].name}
type={props.icons[0].type}
fallbackIcon={props.icons[0].fallbackIcon}
/>
</PressableWithoutFocus>
)}
Expand Down Expand Up @@ -93,6 +94,7 @@ function RoomHeaderAvatars(props) {
containerStyles={[...iconStyle, StyleUtils.getAvatarBorderRadius(CONST.AVATAR_SIZE.LARGE_BORDERED, icon.type)]}
name={icon.name}
type={icon.type}
fallbackIcon={icon.fallbackIcon}
/>
</PressableWithoutFocus>
)}
Expand Down
1 change: 1 addition & 0 deletions src/components/SelectionList/UserListItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function UserListItem({item, isFocused = false, showTooltip, onSelectRow, onDism
source={lodashGet(item, 'avatar.source', '')}
name={lodashGet(item, 'avatar.name', item.text)}
type={lodashGet(item, 'avatar.type', CONST.ICON_TYPE_AVATAR)}
fallbackIcon={lodashGet(item, 'avatar.fallbackIcon')}
/>
);

Expand Down
2 changes: 2 additions & 0 deletions src/components/SubscriptAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function SubscriptAvatar(props) {
size={props.size || CONST.AVATAR_SIZE.DEFAULT}
name={props.mainAvatar.name}
type={props.mainAvatar.type}
fallbackIcon={props.mainAvatar.fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand All @@ -83,6 +84,7 @@ function SubscriptAvatar(props) {
fill={themeColors.iconSuccessFill}
name={props.secondaryAvatar.name}
type={props.secondaryAvatar.type}
fallbackIcon={props.secondaryAvatar.fallbackIcon}
/>
</View>
</UserDetailsTooltip>
Expand Down
1 change: 1 addition & 0 deletions src/components/UserDetailsTooltip/index.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ function UserDetailsTooltip(props) {
source={props.icon ? props.icon.source : UserUtils.getAvatar(userAvatar, userAccountID)}
type={props.icon ? props.icon.type : CONST.ICON_TYPE_AVATAR}
name={props.icon ? props.icon.name : userLogin}
fallbackIcon={lodashGet(props.icon, 'fallbackIcon')}
/>
</View>
<Text style={[styles.mt2, styles.textMicroBold, styles.textReactionSenders, styles.textAlignCenter]}>{title}</Text>
Expand Down
1 change: 1 addition & 0 deletions src/components/avatarPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default PropTypes.shape({
type: PropTypes.oneOf([CONST.ICON_TYPE_AVATAR, CONST.ICON_TYPE_WORKSPACE]),
name: PropTypes.string,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
});
2 changes: 1 addition & 1 deletion src/components/menuItemPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const propTypes = {
interactive: PropTypes.bool,

/** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
fallbackIcon: PropTypes.func,
fallbackIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),

/** Avatars to show on the right of the menu item */
floatRightAvatars: PropTypes.arrayOf(avatarPropTypes),
Expand Down
9 changes: 8 additions & 1 deletion src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ function getIconsForParticipants(participants, personalDetails) {
const accountID = participantsList[i];
const avatarSource = UserUtils.getAvatar(lodashGet(personalDetails, [accountID, 'avatar'], ''), accountID);
const displayNameLogin = lodashGet(personalDetails, [accountID, 'displayName']) || lodashGet(personalDetails, [accountID, 'login'], '');
participantDetails.push([accountID, displayNameLogin, avatarSource]);
participantDetails.push([accountID, displayNameLogin, avatarSource, lodashGet(personalDetails, [accountID, 'fallBackIcon'])]);
}

const sortedParticipantDetails = _.chain(participantDetails)
Expand All @@ -974,6 +974,7 @@ function getIconsForParticipants(participants, personalDetails) {
source: sortedParticipantDetails[i][2],
type: CONST.ICON_TYPE_AVATAR,
name: sortedParticipantDetails[i][1],
fallBackIcon: sortedParticipantDetails[i][3],
};
avatars.push(userIcon);
}
Expand Down Expand Up @@ -1031,6 +1032,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false,
id: parentReportAction.actorAccountID,
type: CONST.ICON_TYPE_AVATAR,
name: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'displayName'], ''),
fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']),
};

return [memberIcon, workspaceIcon];
Expand All @@ -1045,6 +1047,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false,
source: UserUtils.getAvatar(lodashGet(personalDetails, [actorAccountID, 'avatar']), actorAccountID),
name: actorDisplayName,
type: CONST.ICON_TYPE_AVATAR,
fallbackIcon: lodashGet(personalDetails, [parentReportAction.actorAccountID, 'fallbackIcon']),
};

if (isWorkspaceThread(report)) {
Expand All @@ -1059,6 +1062,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false,
source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID),
type: CONST.ICON_TYPE_AVATAR,
name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''),
fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']),
};

if (isWorkspaceTaskReport(report)) {
Expand Down Expand Up @@ -1091,6 +1095,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false,
id: report.ownerAccountID,
type: CONST.ICON_TYPE_AVATAR,
name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''),
fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']),
};
return isExpenseReport(report) ? [memberIcon, workspaceIcon] : [workspaceIcon, memberIcon];
}
Expand All @@ -1100,13 +1105,15 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false,
id: report.managerID,
type: CONST.ICON_TYPE_AVATAR,
name: lodashGet(personalDetails, [report.managerID, 'displayName'], ''),
fallbackIcon: lodashGet(personalDetails, [report.managerID, 'fallbackIcon']),
};

const ownerIcon = {
id: report.ownerAccountID,
source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID),
type: CONST.ICON_TYPE_AVATAR,
name: lodashGet(personalDetails, [report.ownerAccountID, 'displayName'], ''),
fallbackIcon: lodashGet(personalDetails, [report.ownerAccountID, 'fallbackIcon']),
};

return isPayer ? [managerIcon, ownerIcon] : [ownerIcon, managerIcon];
Expand Down
Loading
Loading