Skip to content

Commit 6c53be1

Browse files
authored
Merge pull request #8499 from Expensify/marco-mergeAvatarIconFunctions
merge getReportIcons and getAvatarSources functions
2 parents c8b3177 + 1d3f3b6 commit 6c53be1

14 files changed

+137
-150
lines changed

src/components/MultipleAvatars.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import CONST from '../CONST';
1212

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

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

2828
const defaultProps = {
29-
avatarIcons: [],
29+
icons: [],
3030
size: CONST.AVATAR_SIZE.DEFAULT,
3131
secondAvatarStyle: [StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)],
3232
avatarTooltips: [],
@@ -40,16 +40,16 @@ const MultipleAvatars = (props) => {
4040
...props.secondAvatarStyle,
4141
];
4242

43-
if (!props.avatarIcons.length) {
43+
if (!props.icons.length) {
4444
return null;
4545
}
4646

47-
if (props.avatarIcons.length === 1) {
47+
if (props.icons.length === 1) {
4848
return (
4949
<View style={avatarContainerStyles}>
5050
<Tooltip text={props.avatarTooltips[0]}>
5151
<Avatar
52-
source={props.avatarIcons[0]}
52+
source={props.icons[0]}
5353
size={props.size}
5454
fill={themeColors.iconSuccessFill}
5555
/>
@@ -65,17 +65,17 @@ const MultipleAvatars = (props) => {
6565
>
6666
<Tooltip text={props.avatarTooltips[0]} absolute>
6767
<Image
68-
source={{uri: props.avatarIcons[0]}}
68+
source={{uri: props.icons[0]}}
6969
style={singleAvatarStyles}
7070
/>
7171
</Tooltip>
7272
<View
7373
style={secondAvatarStyles}
7474
>
75-
{props.avatarIcons.length === 2 ? (
75+
{props.icons.length === 2 ? (
7676
<Tooltip text={props.avatarTooltips[1]} absolute>
7777
<Image
78-
source={{uri: props.avatarIcons[1]}}
78+
source={{uri: props.icons[1]}}
7979
style={singleAvatarStyles}
8080
/>
8181
</Tooltip>
@@ -88,7 +88,7 @@ const MultipleAvatars = (props) => {
8888
? styles.avatarInnerTextSmall
8989
: styles.avatarInnerText}
9090
>
91-
{`+${props.avatarIcons.length - 1}`}
91+
{`+${props.icons.length - 1}`}
9292
</Text>
9393
</View>
9494
</Tooltip>

src/components/OptionRow.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ const OptionRow = (props) => {
173173
/>
174174
) : (
175175
<MultipleAvatars
176-
avatarIcons={props.option.icons}
176+
icons={props.option.icons}
177177
size={props.mode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
178178
secondAvatarStyle={[
179179
StyleUtils.getBackgroundAndBorderStyle(props.backgroundColor),

src/components/ReportActionItem/IOUPreview.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ const IOUPreview = (props) => {
139139
</View>
140140
<View style={styles.iouPreviewBoxAvatar}>
141141
<MultipleAvatars
142-
avatarIcons={[managerAvatar, ownerAvatar]}
142+
icons={[managerAvatar, ownerAvatar]}
143143
secondAvatarStyle={[styles.secondAvatarInline]}
144144
avatarTooltips={avatarTooltip}
145145
/>

src/components/RoomHeaderAvatars.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,26 @@ import * as StyleUtils from '../styles/StyleUtils';
1111

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

1616
/** Whether show large Avatars */
1717
shouldShowLargeAvatars: PropTypes.bool,
1818
};
1919

2020
const defaultProps = {
21-
avatarIcons: [],
21+
icons: [],
2222
shouldShowLargeAvatars: false,
2323
};
2424

2525
const RoomHeaderAvatars = (props) => {
26-
if (!props.avatarIcons.length) {
26+
if (!props.icons.length) {
2727
return null;
2828
}
2929

30-
if (props.avatarIcons.length === 1) {
30+
if (props.icons.length === 1) {
3131
return (
3232
<Avatar
33-
source={props.avatarIcons[0]}
33+
source={props.icons[0]}
3434
imageStyles={[styles.avatarLarge]}
3535
fill={themeColors.iconSuccessFill}
3636
size={CONST.AVATAR_SIZE.LARGE}
@@ -43,15 +43,15 @@ const RoomHeaderAvatars = (props) => {
4343
<View style={[styles.flexRow, styles.wAuto, styles.justifyContentCenter, styles.alignItemsCenter]}>
4444
<View style={styles.leftSideLargeAvatar}>
4545
<Avatar
46-
source={props.avatarIcons[1]}
46+
source={props.icons[1]}
4747
imageStyles={[styles.avatarLarge]}
4848
size={CONST.AVATAR_SIZE.LARGE}
4949
fill={themeColors.iconSuccessFill}
5050
/>
5151
</View>
5252
<View style={[styles.rightSideLargeAvatar, StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)]}>
5353
<Avatar
54-
source={props.avatarIcons[0]}
54+
source={props.icons[0]}
5555
imageStyles={[styles.avatarLarge]}
5656
size={CONST.AVATAR_SIZE.LARGE}
5757
/>
@@ -60,15 +60,15 @@ const RoomHeaderAvatars = (props) => {
6060
);
6161
}
6262

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

71-
{index === CONST.REPORT.MAX_PREVIEW_AVATARS - 1 && props.avatarIcons.length - CONST.REPORT.MAX_PREVIEW_AVATARS !== 0 && (
71+
{index === CONST.REPORT.MAX_PREVIEW_AVATARS - 1 && props.icons.length - CONST.REPORT.MAX_PREVIEW_AVATARS !== 0 && (
7272
<>
7373
<View
7474
style={[
@@ -77,7 +77,7 @@ const RoomHeaderAvatars = (props) => {
7777
]}
7878
/>
7979
<Text style={styles.avatarInnerTextChat}>
80-
{`+${props.avatarIcons.length - CONST.REPORT.MAX_PREVIEW_AVATARS}`}
80+
{`+${props.icons.length - CONST.REPORT.MAX_PREVIEW_AVATARS}`}
8181
</Text>
8282
</>
8383
)}

src/libs/OptionsListUtils.js

Lines changed: 10 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import CONST from '../CONST';
99
import * as ReportUtils from './reportUtils';
1010
import * as Localize from './Localize';
1111
import Permissions from './Permissions';
12-
import md5 from './md5';
13-
import * as Expensicons from '../components/Icon/Expensicons';
1412

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

81-
/**
82-
* Helper method to return a default avatar
83-
*
84-
* @param {String} [login]
85-
* @returns {String}
86-
*/
87-
function getDefaultAvatar(login = '') {
88-
// There are 8 possible default avatars, so we choose which one this user has based
89-
// on a simple hash of their login (which is converted from HEX to INT)
90-
const loginHashBucket = (parseInt(md5(login).substring(0, 4), 16) % 8) + 1;
91-
return `${CONST.CLOUDFRONT_URL}/images/avatars/avatar_${loginHashBucket}.png`;
92-
}
93-
9479
// We are initializing a default avatar here so that we use the same default color for each user we are inviting. This
9580
// will update when the OptionsListUtils re-loads. But will stay the same color for the life of the JS session.
96-
const defaultAvatarForUserToInvite = getDefaultAvatar();
81+
const defaultAvatarForUserToInvite = ReportUtils.getDefaultAvatar();
9782

9883
/**
9984
* Adds expensify SMS domain (@expensify.sms) if login is a phone number and if it's not included yet
@@ -124,7 +109,7 @@ function getPersonalDetailsForLogins(logins, personalDetails) {
124109
personalDetail = {
125110
login,
126111
displayName: login,
127-
avatar: getDefaultAvatar(login),
112+
avatar: ReportUtils.getDefaultAvatar(login),
128113
};
129114
}
130115

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

209-
/**
210-
* Get the Avatar urls or return the icon according to the chat type
211-
*
212-
* @param {Object} report
213-
* @returns {Array<*>}
214-
*/
215-
function getAvatarSources(report) {
216-
return _.map(lodashGet(report, 'icons', ['']), (source) => {
217-
if (source) {
218-
return source;
219-
}
220-
if (ReportUtils.isArchivedRoom(report)) {
221-
return Expensicons.DeletedRoomAvatar;
222-
}
223-
if (ReportUtils.isAdminRoom(report)) {
224-
return Expensicons.AdminRoomAvatar;
225-
}
226-
if (ReportUtils.isAnnounceRoom(report)) {
227-
return Expensicons.AnnounceRoomAvatar;
228-
}
229-
if (ReportUtils.isChatRoom(report)) {
230-
return Expensicons.ActiveRoomAvatar;
231-
}
232-
if (ReportUtils.isPolicyExpenseChat(report)) {
233-
return Expensicons.Workspace;
234-
}
235-
return Expensicons.Profile;
236-
});
237-
}
238-
239194
/**
240195
* Creates a report list option
241196
*
242-
* @param {Array<Object>} personalDetailList
197+
* @param {Array<String>} logins
198+
* @param {Object} personalDetails
243199
* @param {Object} report
244200
* @param {Object} options
245201
* @param {Boolean} [options.showChatPreviewLine]
246202
* @param {Boolean} [options.forcePolicyNamePreview]
247203
* @returns {Object}
248204
*/
249-
function createOption(personalDetailList, report, {
205+
function createOption(logins, personalDetails, report, {
250206
showChatPreviewLine = false, forcePolicyNamePreview = false,
251207
}) {
252208
const isChatRoom = ReportUtils.isChatRoom(report);
253209
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report);
210+
const personalDetailList = getPersonalDetailsForLogins(logins, personalDetails);
254211
const isArchivedRoom = ReportUtils.isArchivedRoom(report);
255212
const hasMultipleParticipants = personalDetailList.length > 1 || isChatRoom || isPolicyExpenseChat;
256213
const personalDetail = personalDetailList[0];
@@ -271,7 +228,6 @@ function createOption(personalDetailList, report, {
271228

272229
const tooltipText = ReportUtils.getReportParticipantsTitle(lodashGet(report, ['participants'], []));
273230
const subtitle = ReportUtils.getChatRoomSubtitle(report, policies);
274-
let icons = getAvatarSources(report);
275231
let text;
276232
let alternateText;
277233
if (isChatRoom || isPolicyExpenseChat) {
@@ -287,15 +243,11 @@ function createOption(personalDetailList, report, {
287243
alternateText = (showChatPreviewLine && lastMessageText)
288244
? lastMessageText
289245
: Str.removeSMSDomain(personalDetail.login);
290-
if (!report) {
291-
// If the report doesn't exist then we're creating a list of users to invite (using the personalDetailList)
292-
icons = [personalDetail.avatar];
293-
}
294246
}
295247
return {
296248
text,
297249
alternateText,
298-
icons,
250+
icons: ReportUtils.getIcons(report, personalDetails, policies, lodashGet(personalDetail, ['avatar'])),
299251
tooltipText,
300252
ownerEmail: lodashGet(report, ['ownerEmail']),
301253
subtitle,
@@ -471,23 +423,21 @@ function getOptions(reports, personalDetails, activeReportID, {
471423
return;
472424
}
473425

474-
const reportPersonalDetails = getPersonalDetailsForLogins(logins, personalDetails);
475-
476426
// Save the report in the map if this is a single participant so we can associate the reportID with the
477427
// personal detail option later. Individuals should not be associated with single participant
478428
// policyExpenseChats or chatRooms since those are not people.
479429
if (logins.length <= 1 && !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatRoom(report)) {
480430
reportMapForLogins[logins[0]] = report;
481431
}
482432
const isSearchingSomeonesPolicyExpenseChat = !report.isOwnPolicyExpenseChat && searchValue !== '';
483-
allReportOptions.push(createOption(reportPersonalDetails, report, {
433+
allReportOptions.push(createOption(logins, personalDetails, report, {
484434
showChatPreviewLine,
485435
forcePolicyNamePreview: isPolicyExpenseChat ? isSearchingSomeonesPolicyExpenseChat : forcePolicyNamePreview,
486436
}));
487437
});
488438

489439
const allPersonalDetailsOptions = _.map(personalDetails, personalDetail => (
490-
createOption([personalDetail], reportMapForLogins[personalDetail.login], {
440+
createOption([personalDetail.login], personalDetails, reportMapForLogins[personalDetail.login], {
491441
showChatPreviewLine,
492442
forcePolicyNamePreview,
493443
})
@@ -603,8 +553,7 @@ function getOptions(reports, personalDetails, activeReportID, {
603553
const login = (Str.isValidPhone(searchValue) && !searchValue.includes('+'))
604554
? `+${countryCodeByIP}${searchValue}`
605555
: searchValue;
606-
const userInvitePersonalDetails = getPersonalDetailsForLogins([login], personalDetails);
607-
userToInvite = createOption(userInvitePersonalDetails, null, {
556+
userToInvite = createOption([login], personalDetails, null, {
608557
showChatPreviewLine,
609558
});
610559
userToInvite.icons = [defaultAvatarForUserToInvite];
@@ -817,47 +766,9 @@ function getCurrencyListForSections(currencyOptions, searchValue) {
817766
};
818767
}
819768

820-
/**
821-
* Returns the appropriate icons for the given chat report using personalDetails if applicable
822-
*
823-
* @param {Object} report
824-
* @param {Object} personalDetails
825-
* @returns {Array<String>}
826-
*/
827-
function getReportIcons(report, personalDetails) {
828-
// Default rooms have a specific avatar so we can return any non-empty array
829-
if (ReportUtils.isChatRoom(report)) {
830-
return [''];
831-
}
832-
833-
if (ReportUtils.isPolicyExpenseChat(report)) {
834-
const policyExpenseChatAvatarURL = lodashGet(policies, [
835-
`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'avatarURL',
836-
]);
837-
838-
// Return the workspace avatar if the user is the owner of the policy expense chat
839-
if (report.isOwnPolicyExpenseChat) {
840-
return [policyExpenseChatAvatarURL];
841-
}
842-
843-
// If the user is an admin, return avatar url of the other participant of the report
844-
// (their workspace chat) and the avatar url of the workspace
845-
return [lodashGet(personalDetails, [report.ownerEmail, 'avatarThumbnail']), policyExpenseChatAvatarURL];
846-
}
847-
848-
const sortedParticipants = _.map(report.participants, dmParticipant => ({
849-
firstName: lodashGet(personalDetails, [dmParticipant, 'firstName'], ''),
850-
avatar: lodashGet(personalDetails, [dmParticipant, 'avatarThumbnail'], '')
851-
|| getDefaultAvatar(dmParticipant),
852-
}))
853-
.sort((first, second) => first.firstName - second.firstName);
854-
return _.map(sortedParticipants, item => item.avatar);
855-
}
856-
857769
export {
858770
addSMSDomainIfPhoneNumber,
859771
isCurrentUser,
860-
getAvatarSources,
861772
getSearchOptions,
862773
getNewChatOptions,
863774
getSidebarOptions,
@@ -866,6 +777,4 @@ export {
866777
getCurrencyListForSections,
867778
getIOUConfirmationOptionsFromMyPersonalDetail,
868779
getIOUConfirmationOptionsFromParticipants,
869-
getDefaultAvatar,
870-
getReportIcons,
871780
};

0 commit comments

Comments
 (0)