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

merge getReportIcons and getAvatarSources functions #8499

Merged
merged 33 commits into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4dd6ae4
avoid storing report icons into Onyx
marcochavezf Apr 5, 2022
383c9d1
get avatar source directly from report.icons
marcochavezf Apr 5, 2022
29e1c2e
remove getReportIcons from PersonalDetails
marcochavezf Apr 5, 2022
e80e04a
use getReportIcons in getAvatarSources
marcochavezf Apr 5, 2022
2ecf2e2
get personalDetails from Onyx to get avatar urls
marcochavezf Apr 5, 2022
afcbf42
merge getReportIcons and getAvatarSources into one function
marcochavezf Apr 5, 2022
c118096
fix single avatars by returning an array
marcochavezf Apr 5, 2022
7ec2c8f
fix default icon component if avatar is an empty string
marcochavezf Apr 5, 2022
08e93ef
add comment for group chats
marcochavezf Apr 5, 2022
84858e7
return empty string for firstName in sortedParticipants
marcochavezf Apr 5, 2022
6e3ef16
change fn name getAvatarSources to getReportIcons
marcochavezf Apr 5, 2022
3aac326
add defaultIcon param to getReportIcons
marcochavezf Apr 5, 2022
caf72a5
remove personalDetails subscription and add it as param in getReportI…
marcochavezf Apr 7, 2022
e7404de
pass personalDetails for getReportIcons for ReportActionItemCreated
marcochavezf Apr 7, 2022
cf6dfda
add personalDetails param to getReportIcons usages
marcochavezf Apr 7, 2022
93ff338
move personalDetails to createOption to pass it to getReportIcons
marcochavezf Apr 7, 2022
1981e43
move getReportIcons to reportUtils
marcochavezf Apr 7, 2022
0212cc4
fix errors in getReportIcons
marcochavezf Apr 7, 2022
773fe51
move getDefaultAvatar to reportUtils
marcochavezf Apr 7, 2022
2a42503
fix usages of getDefaultAvatar
marcochavezf Apr 7, 2022
d044382
fix getDefaultAvatar in ProfilePage
marcochavezf Apr 7, 2022
785675c
fix usages of getReportIcons
marcochavezf Apr 7, 2022
68d07a4
remove unnecessary jsdoc params
marcochavezf Apr 7, 2022
36555a2
add policies as param to getReportIcons
marcochavezf Apr 7, 2022
0cea30b
include policies prop via withOnyx to ReportActionItemCreated
marcochavezf Apr 7, 2022
8ba167f
pass policies in when getReportIcons is called
marcochavezf Apr 7, 2022
bba318f
change const name avatarIcons to reportIcons
marcochavezf Apr 7, 2022
6c63d9b
fix issue when personalDetail is not defined
marcochavezf Apr 7, 2022
e16e0ef
Merge branch 'main' into marco-mergeAvatarIconFunctions
marcochavezf Apr 7, 2022
0967f47
rename avatarIcons to icons in MultipleAvatars
marcochavezf Apr 11, 2022
652c131
change avatarIcons to icons in RoomHeaderAvatars
marcochavezf Apr 11, 2022
e5b823d
update usages of RoomHeaderAvatars
marcochavezf Apr 11, 2022
1d3f3b6
change getReportIcons to getIcons
marcochavezf Apr 11, 2022
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
18 changes: 9 additions & 9 deletions src/components/MultipleAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import CONST from '../CONST';

const propTypes = {
/** Array of avatar URLs or icons */
avatarIcons: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.func])),
icons: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.func])),

/** Set the size of avatars */
size: PropTypes.oneOf(_.values(CONST.AVATAR_SIZE)),
Expand All @@ -26,7 +26,7 @@ const propTypes = {
};

const defaultProps = {
avatarIcons: [],
icons: [],
size: CONST.AVATAR_SIZE.DEFAULT,
secondAvatarStyle: [StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)],
avatarTooltips: [],
Expand All @@ -40,16 +40,16 @@ const MultipleAvatars = (props) => {
...props.secondAvatarStyle,
];

if (!props.avatarIcons.length) {
if (!props.icons.length) {
return null;
}

if (props.avatarIcons.length === 1) {
if (props.icons.length === 1) {
return (
<View style={avatarContainerStyles}>
<Tooltip text={props.avatarTooltips[0]}>
<Avatar
source={props.avatarIcons[0]}
source={props.icons[0]}
size={props.size}
fill={themeColors.iconSuccessFill}
/>
Expand All @@ -65,17 +65,17 @@ const MultipleAvatars = (props) => {
>
<Tooltip text={props.avatarTooltips[0]} absolute>
<Image
source={{uri: props.avatarIcons[0]}}
source={{uri: props.icons[0]}}
style={singleAvatarStyles}
/>
</Tooltip>
<View
style={secondAvatarStyles}
>
{props.avatarIcons.length === 2 ? (
{props.icons.length === 2 ? (
<Tooltip text={props.avatarTooltips[1]} absolute>
<Image
source={{uri: props.avatarIcons[1]}}
source={{uri: props.icons[1]}}
style={singleAvatarStyles}
/>
</Tooltip>
Expand All @@ -88,7 +88,7 @@ const MultipleAvatars = (props) => {
? styles.avatarInnerTextSmall
: styles.avatarInnerText}
>
{`+${props.avatarIcons.length - 1}`}
{`+${props.icons.length - 1}`}
</Text>
</View>
</Tooltip>
Expand Down
2 changes: 1 addition & 1 deletion src/components/OptionRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ const OptionRow = (props) => {
/>
) : (
<MultipleAvatars
avatarIcons={props.option.icons}
icons={props.option.icons}
size={props.mode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
secondAvatarStyle={[
StyleUtils.getBackgroundAndBorderStyle(props.backgroundColor),
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReportActionItem/IOUPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const IOUPreview = (props) => {
</View>
<View style={styles.iouPreviewBoxAvatar}>
<MultipleAvatars
avatarIcons={[managerAvatar, ownerAvatar]}
icons={[managerAvatar, ownerAvatar]}
secondAvatarStyle={[styles.secondAvatarInline]}
avatarTooltips={avatarTooltip}
/>
Expand Down
22 changes: 11 additions & 11 deletions src/components/RoomHeaderAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ import * as StyleUtils from '../styles/StyleUtils';

const propTypes = {
/** Array of avatar URLs or icons */
avatarIcons: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.func])),
icons: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.func])),

/** Whether show large Avatars */
shouldShowLargeAvatars: PropTypes.bool,
};

const defaultProps = {
avatarIcons: [],
icons: [],
shouldShowLargeAvatars: false,
};

const RoomHeaderAvatars = (props) => {
if (!props.avatarIcons.length) {
if (!props.icons.length) {
return null;
}

if (props.avatarIcons.length === 1) {
if (props.icons.length === 1) {
return (
<Avatar
source={props.avatarIcons[0]}
source={props.icons[0]}
imageStyles={[styles.avatarLarge]}
fill={themeColors.iconSuccessFill}
size={CONST.AVATAR_SIZE.LARGE}
Expand All @@ -43,15 +43,15 @@ const RoomHeaderAvatars = (props) => {
<View style={[styles.flexRow, styles.wAuto, styles.justifyContentCenter, styles.alignItemsCenter]}>
<View style={styles.leftSideLargeAvatar}>
<Avatar
source={props.avatarIcons[1]}
source={props.icons[1]}
imageStyles={[styles.avatarLarge]}
size={CONST.AVATAR_SIZE.LARGE}
fill={themeColors.iconSuccessFill}
/>
</View>
<View style={[styles.rightSideLargeAvatar, StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)]}>
<Avatar
source={props.avatarIcons[0]}
source={props.icons[0]}
imageStyles={[styles.avatarLarge]}
size={CONST.AVATAR_SIZE.LARGE}
/>
Expand All @@ -60,15 +60,15 @@ const RoomHeaderAvatars = (props) => {
);
}

const avatarIconsToDisplay = props.avatarIcons.slice(0, CONST.REPORT.MAX_PREVIEW_AVATARS);
const iconsToDisplay = props.icons.slice(0, CONST.REPORT.MAX_PREVIEW_AVATARS);
return (
<View pointerEvents="none">
<View style={[styles.flexRow, styles.wAuto, styles.ml3]}>
{_.map(avatarIconsToDisplay, (val, index) => (
{_.map(iconsToDisplay, (val, index) => (
<View key={val} style={[styles.justifyContentCenter, styles.alignItemsCenter]}>
<Image source={{uri: val}} style={[styles.roomHeaderAvatar]} />

{index === CONST.REPORT.MAX_PREVIEW_AVATARS - 1 && props.avatarIcons.length - CONST.REPORT.MAX_PREVIEW_AVATARS !== 0 && (
{index === CONST.REPORT.MAX_PREVIEW_AVATARS - 1 && props.icons.length - CONST.REPORT.MAX_PREVIEW_AVATARS !== 0 && (
<>
<View
style={[
Expand All @@ -77,7 +77,7 @@ const RoomHeaderAvatars = (props) => {
]}
/>
<Text style={styles.avatarInnerTextChat}>
{`+${props.avatarIcons.length - CONST.REPORT.MAX_PREVIEW_AVATARS}`}
{`+${props.icons.length - CONST.REPORT.MAX_PREVIEW_AVATARS}`}
</Text>
</>
)}
Expand Down
111 changes: 10 additions & 101 deletions src/libs/OptionsListUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import CONST from '../CONST';
import * as ReportUtils from './reportUtils';
import * as Localize from './Localize';
import Permissions from './Permissions';
import md5 from './md5';
import * as Expensicons from '../components/Icon/Expensicons';

/**
* OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can
Expand Down Expand Up @@ -78,22 +76,9 @@ Onyx.connect({
},
});

/**
* Helper method to return a default avatar
*
* @param {String} [login]
* @returns {String}
*/
function getDefaultAvatar(login = '') {
// There are 8 possible default avatars, so we choose which one this user has based
// on a simple hash of their login (which is converted from HEX to INT)
const loginHashBucket = (parseInt(md5(login).substring(0, 4), 16) % 8) + 1;
return `${CONST.CLOUDFRONT_URL}/images/avatars/avatar_${loginHashBucket}.png`;
}

// We are initializing a default avatar here so that we use the same default color for each user we are inviting. This
// will update when the OptionsListUtils re-loads. But will stay the same color for the life of the JS session.
const defaultAvatarForUserToInvite = getDefaultAvatar();
const defaultAvatarForUserToInvite = ReportUtils.getDefaultAvatar();

/**
* Adds expensify SMS domain (@expensify.sms) if login is a phone number and if it's not included yet
Expand Down Expand Up @@ -124,7 +109,7 @@ function getPersonalDetailsForLogins(logins, personalDetails) {
personalDetail = {
login,
displayName: login,
avatar: getDefaultAvatar(login),
avatar: ReportUtils.getDefaultAvatar(login),
};
}

Expand Down Expand Up @@ -206,51 +191,23 @@ function hasReportDraftComment(report) {
&& lodashGet(reportsWithDraft, `${ONYXKEYS.COLLECTION.REPORTS_WITH_DRAFT}${report.reportID}`, false);
}

/**
* Get the Avatar urls or return the icon according to the chat type
*
* @param {Object} report
* @returns {Array<*>}
*/
function getAvatarSources(report) {
return _.map(lodashGet(report, 'icons', ['']), (source) => {
if (source) {
return source;
}
if (ReportUtils.isArchivedRoom(report)) {
return Expensicons.DeletedRoomAvatar;
}
if (ReportUtils.isAdminRoom(report)) {
return Expensicons.AdminRoomAvatar;
}
if (ReportUtils.isAnnounceRoom(report)) {
return Expensicons.AnnounceRoomAvatar;
}
if (ReportUtils.isChatRoom(report)) {
return Expensicons.ActiveRoomAvatar;
}
if (ReportUtils.isPolicyExpenseChat(report)) {
return Expensicons.Workspace;
}
return Expensicons.Profile;
});
}

/**
* Creates a report list option
*
* @param {Array<Object>} personalDetailList
* @param {Array<String>} logins
* @param {Object} personalDetails
* @param {Object} report
* @param {Object} options
* @param {Boolean} [options.showChatPreviewLine]
* @param {Boolean} [options.forcePolicyNamePreview]
* @returns {Object}
*/
function createOption(personalDetailList, report, {
function createOption(logins, personalDetails, report, {
showChatPreviewLine = false, forcePolicyNamePreview = false,
}) {
const isChatRoom = ReportUtils.isChatRoom(report);
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report);
const personalDetailList = getPersonalDetailsForLogins(logins, personalDetails);
const isArchivedRoom = ReportUtils.isArchivedRoom(report);
const hasMultipleParticipants = personalDetailList.length > 1 || isChatRoom || isPolicyExpenseChat;
const personalDetail = personalDetailList[0];
Expand All @@ -271,7 +228,6 @@ function createOption(personalDetailList, report, {

const tooltipText = ReportUtils.getReportParticipantsTitle(lodashGet(report, ['participants'], []));
const subtitle = ReportUtils.getChatRoomSubtitle(report, policies);
let icons = getAvatarSources(report);
let text;
let alternateText;
if (isChatRoom || isPolicyExpenseChat) {
Expand All @@ -287,15 +243,11 @@ function createOption(personalDetailList, report, {
alternateText = (showChatPreviewLine && lastMessageText)
? lastMessageText
: Str.removeSMSDomain(personalDetail.login);
if (!report) {
// If the report doesn't exist then we're creating a list of users to invite (using the personalDetailList)
icons = [personalDetail.avatar];
}
}
return {
text,
alternateText,
icons,
icons: ReportUtils.getIcons(report, personalDetails, policies, lodashGet(personalDetail, ['avatar'])),
tooltipText,
ownerEmail: lodashGet(report, ['ownerEmail']),
subtitle,
Expand Down Expand Up @@ -470,23 +422,21 @@ function getOptions(reports, personalDetails, activeReportID, {
return;
}

const reportPersonalDetails = getPersonalDetailsForLogins(logins, personalDetails);

// Save the report in the map if this is a single participant so we can associate the reportID with the
// personal detail option later. Individuals should not be associated with single participant
// policyExpenseChats or chatRooms since those are not people.
if (logins.length <= 1 && !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatRoom(report)) {
reportMapForLogins[logins[0]] = report;
}
const isSearchingSomeonesPolicyExpenseChat = !report.isOwnPolicyExpenseChat && searchValue !== '';
allReportOptions.push(createOption(reportPersonalDetails, report, {
allReportOptions.push(createOption(logins, personalDetails, report, {
showChatPreviewLine,
forcePolicyNamePreview: isPolicyExpenseChat ? isSearchingSomeonesPolicyExpenseChat : forcePolicyNamePreview,
}));
});

const allPersonalDetailsOptions = _.map(personalDetails, personalDetail => (
createOption([personalDetail], reportMapForLogins[personalDetail.login], {
createOption([personalDetail.login], personalDetails, reportMapForLogins[personalDetail.login], {
showChatPreviewLine,
forcePolicyNamePreview,
})
Expand Down Expand Up @@ -602,8 +552,7 @@ function getOptions(reports, personalDetails, activeReportID, {
const login = (Str.isValidPhone(searchValue) && !searchValue.includes('+'))
? `+${countryCodeByIP}${searchValue}`
: searchValue;
const userInvitePersonalDetails = getPersonalDetailsForLogins([login], personalDetails);
userToInvite = createOption(userInvitePersonalDetails, null, {
userToInvite = createOption([login], personalDetails, null, {
showChatPreviewLine,
});
userToInvite.icons = [defaultAvatarForUserToInvite];
Expand Down Expand Up @@ -816,47 +765,9 @@ function getCurrencyListForSections(currencyOptions, searchValue) {
};
}

/**
* Returns the appropriate icons for the given chat report using personalDetails if applicable
*
* @param {Object} report
* @param {Object} personalDetails
* @returns {Array<String>}
*/
function getReportIcons(report, personalDetails) {
marcochavezf marked this conversation as resolved.
Show resolved Hide resolved
// Default rooms have a specific avatar so we can return any non-empty array
if (ReportUtils.isChatRoom(report)) {
return [''];
}

if (ReportUtils.isPolicyExpenseChat(report)) {
const policyExpenseChatAvatarURL = lodashGet(policies, [
`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'avatarURL',
]);

// Return the workspace avatar if the user is the owner of the policy expense chat
if (report.isOwnPolicyExpenseChat) {
return [policyExpenseChatAvatarURL];
}

// If the user is an admin, return avatar url of the other participant of the report
// (their workspace chat) and the avatar url of the workspace
return [lodashGet(personalDetails, [report.ownerEmail, 'avatarThumbnail']), policyExpenseChatAvatarURL];
}

const sortedParticipants = _.map(report.participants, dmParticipant => ({
firstName: lodashGet(personalDetails, [dmParticipant, 'firstName'], ''),
avatar: lodashGet(personalDetails, [dmParticipant, 'avatarThumbnail'], '')
|| getDefaultAvatar(dmParticipant),
}))
.sort((first, second) => first.firstName - second.firstName);
return _.map(sortedParticipants, item => item.avatar);
}

export {
addSMSDomainIfPhoneNumber,
isCurrentUser,
getAvatarSources,
getSearchOptions,
getNewChatOptions,
getSidebarOptions,
Expand All @@ -865,6 +776,4 @@ export {
getCurrencyListForSections,
getIOUConfirmationOptionsFromMyPersonalDetail,
getIOUConfirmationOptionsFromParticipants,
getDefaultAvatar,
getReportIcons,
};
Loading