diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index 963702b38aa6..75117cd4cb42 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -35,12 +35,6 @@ const propTypes = { /** Personal details of all users */ personalDetails: PropTypes.objectOf(personalDetailsPropType), - /** The list of policies the user has access to. */ - policies: PropTypes.objectOf(PropTypes.shape({ - /** The name of the policy */ - name: PropTypes.string, - })), - ...withLocalizePropTypes, }; @@ -51,7 +45,6 @@ const defaultProps = { }, }, personalDetails: {}, - policies: {}, }; const ArchivedReportFooter = (props) => { @@ -72,7 +65,7 @@ const ArchivedReportFooter = (props) => { text={props.translate(`reportArchiveReasons.${archiveReason}`, { displayName: `${displayName}`, oldDisplayName: `${oldDisplayName}`, - policyName: `${ReportUtils.getPolicyName(props.report, props.policies)}`, + policyName: `${ReportUtils.getPolicyName(props.report)}`, })} shouldRenderHTML={archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT} shouldShowIcon @@ -90,9 +83,6 @@ export default compose( personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS, }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, reportClosedAction: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, canEvict: false, diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index f0721af2c2ea..6328fbbe58f7 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -38,12 +38,6 @@ const propTypes = { /** All of the personal details for everyone */ personalDetails: PropTypes.objectOf(personalDetailsPropTypes), - /** The policies which the user has access to and which the report could be tied to */ - policies: PropTypes.shape({ - /** The policy name */ - name: PropTypes.string, - }), - /** List of betas available to current user */ betas: PropTypes.arrayOf(PropTypes.string), @@ -52,7 +46,6 @@ const propTypes = { const defaultProps = { report: {}, - policies: {}, personalDetails: {}, betas: [], }; @@ -67,7 +60,7 @@ const ReportWelcomeText = (props) => { OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails), isMultipleParticipant, ); - const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report, props.policies); + const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report); const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(props.report, participants, props.betas); return ( <> @@ -90,7 +83,7 @@ const ReportWelcomeText = (props) => { {props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')} - {ReportUtils.getPolicyName(props.report, props.policies)} + {ReportUtils.getPolicyName(props.report)} {props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')} @@ -103,7 +96,7 @@ const ReportWelcomeText = (props) => { {roomWelcomeMessage.phrase1} Navigation.navigate(ROUTES.getReportDetailsRoute(props.report.reportID))}> - {ReportUtils.getReportName(props.report, props.policies)} + {ReportUtils.getReportName(props.report)} {roomWelcomeMessage.phrase2} @@ -156,8 +149,5 @@ export default compose( personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS, }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, }), )(ReportWelcomeText); diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 8e8b0e7c4a7a..6c9dbac34d71 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -281,7 +281,7 @@ function getSearchText(report, reportName, personalDetailList, isChatRoomOrPolic Array.prototype.push.apply(searchTerms, reportName.split(/[,\s]/)); if (isChatRoomOrPolicyExpenseChat) { - const chatRoomSubtitle = ReportUtils.getChatRoomSubtitle(report, policies); + const chatRoomSubtitle = ReportUtils.getChatRoomSubtitle(report); Array.prototype.push.apply(searchTerms, chatRoomSubtitle.split(/[,\s]/)); } else { @@ -401,7 +401,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, { result.hasOutstandingIOU = report.hasOutstandingIOU; hasMultipleParticipants = personalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; - subtitle = ReportUtils.getChatRoomSubtitle(report, policies); + subtitle = ReportUtils.getChatRoomSubtitle(report); let lastMessageTextFromReport = ''; if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml})) { @@ -421,7 +421,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, { || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { displayName: archiveReason.displayName || report.lastActorEmail, - policyName: ReportUtils.getPolicyName(report, policies), + policyName: ReportUtils.getPolicyName(report), }); } @@ -434,7 +434,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, { ? lastMessageText : LocalePhoneNumber.formatPhoneNumber(personalDetail.login); } - reportName = ReportUtils.getReportName(report, policies); + reportName = ReportUtils.getReportName(report); } else { const login = logins[0]; reportName = ReportUtils.getDisplayNameForParticipant(login); @@ -453,7 +453,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, { result.text = reportName; result.searchText = getSearchText(report, reportName, personalDetailList, result.isChatRoom || result.isPolicyExpenseChat); - result.icons = ReportUtils.getIcons(report, personalDetails, policies, ReportUtils.getAvatar(personalDetail.avatar, personalDetail.login)); + result.icons = ReportUtils.getIcons(report, personalDetails, ReportUtils.getAvatar(personalDetail.avatar, personalDetail.login)); result.subtitle = subtitle; return result; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 38e8efcf86a9..2c5207a40429 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -78,6 +78,13 @@ Onyx.connect({ callback: val => doesDomainHaveApprovedAccountant = lodashGet(val, 'doesDomainHaveApprovedAccountant', false), }); +let allPolicies; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY, + waitForCollectionCallback: true, + callback: val => allPolicies = val, +}); + function getChatType(report) { return report ? report.chatType : ''; } @@ -358,21 +365,20 @@ function isArchivedRoom(report) { * @param {String} report.policyID * @param {String} report.oldPolicyName * @param {String} report.policyName - * @param {Object} policies must have Onyxkey prefix (i.e 'policy_') for keys * @returns {String} */ -function getPolicyName(report, policies) { +function getPolicyName(report) { // Public rooms send back the policy name with the reportSummary, // since they can also be accessed by people who aren't in the workspace if (report.policyName) { return report.policyName; } - if (_.isEmpty(policies)) { + if (!allPolicies || _.size(allPolicies) === 0) { return Localize.translateLocal('workspace.common.unavailable'); } - const policy = policies[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; + const policy = allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`]; if (!policy) { return report.oldPolicyName || Localize.translateLocal('workspace.common.unavailable'); } @@ -404,10 +410,9 @@ function isPolicyExpenseChatAdmin(report, policies) { /** * Get either the policyName or domainName the chat is tied to * @param {Object} report - * @param {Object} policiesMap must have onyxkey prefix (i.e 'policy_') for keys * @returns {String} */ -function getChatRoomSubtitle(report, policiesMap) { +function getChatRoomSubtitle(report) { if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; } @@ -421,19 +426,18 @@ function getChatRoomSubtitle(report, policiesMap) { if (isArchivedRoom(report)) { return report.oldPolicyName || ''; } - return getPolicyName(report, policiesMap); + return getPolicyName(report); } /** * Get welcome message based on room type * @param {Object} report - * @param {Object} policiesMap must have Onyxkey prefix (i.e 'policy_') for keys * @returns {Object} */ -function getRoomWelcomeMessage(report, policiesMap) { +function getRoomWelcomeMessage(report) { const welcomeMessage = {}; - const workspaceName = getPolicyName(report, policiesMap); + const workspaceName = getPolicyName(report); if (isArchivedRoom(report)) { welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfArchivedRoomPartOne'); @@ -663,11 +667,10 @@ function getSmallSizeAvatar(avatarURL, login) { * * @param {Object} report * @param {Object} personalDetails - * @param {Object} policies * @param {*} [defaultIcon] * @returns {Array<*>} */ -function getIcons(report, personalDetails, policies, defaultIcon = null) { +function getIcons(report, personalDetails, defaultIcon = null) { const result = { source: '', type: CONST.ICON_TYPE_AVATAR, @@ -703,11 +706,11 @@ function getIcons(report, personalDetails, policies, defaultIcon = null) { return [result]; } if (isPolicyExpenseChat(report)) { - const workspaceName = lodashGet(policies, [ + const workspaceName = lodashGet(allPolicies, [ `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'name', ]); - const policyExpenseChatAvatarSource = lodashGet(policies, [ + const policyExpenseChatAvatarSource = lodashGet(allPolicies, [ `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'avatar', ]) || getDefaultWorkspaceAvatar(workspaceName); @@ -837,18 +840,17 @@ function getDisplayNamesWithTooltips(participants, isMultipleParticipantReport) * Get the title for a policy expense chat which depends on the role of the policy member seeing this report * * @param {Object} report - * @param {Object} [policies] * @returns {String} */ -function getPolicyExpenseChatName(report, policies = {}) { +function getPolicyExpenseChatName(report) { const reportOwnerDisplayName = getDisplayNameForParticipant(report.ownerEmail) || report.ownerEmail || report.reportName; // If the policy expense chat is owned by this user, use the name of the policy as the report name. if (report.isOwnPolicyExpenseChat) { - return getPolicyName(report, policies); + return getPolicyName(report); } - const policyExpenseChatRole = lodashGet(policies, [ + const policyExpenseChatRole = lodashGet(allPolicies, [ `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, 'role', ]) || 'user'; @@ -858,7 +860,7 @@ function getPolicyExpenseChatName(report, policies = {}) { const lastAction = ReportActionsUtils.getLastVisibleAction(report.reportID); const archiveReason = (lastAction && lastAction.originalMessage && lastAction.originalMessage.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED && policyExpenseChatRole !== CONST.POLICY.ROLE.ADMIN) { - return getPolicyName(report, policies); + return getPolicyName(report); } } @@ -870,17 +872,16 @@ function getPolicyExpenseChatName(report, policies = {}) { * Get the title for a report. * * @param {Object} report - * @param {Object} [policies] * @returns {String} */ -function getReportName(report, policies = {}) { +function getReportName(report) { let formattedName; if (isChatRoom(report)) { formattedName = report.reportName; } if (isPolicyExpenseChat(report)) { - formattedName = getPolicyExpenseChatName(report, policies); + formattedName = getPolicyExpenseChatName(report); } if (isArchivedRoom(report)) { diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index ba0db3d8fd2d..f61ee6986fb5 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -114,7 +114,7 @@ function getOrderedReportIDs(reportIDFromRoute) { // However, this code needs to be very performant to handle thousands of reports, so in the interest of speed, we're just going to disable this lint rule and add // the reportDisplayName property to the report object directly. // eslint-disable-next-line no-param-reassign - report.displayName = ReportUtils.getReportName(report, policies); + report.displayName = ReportUtils.getReportName(report); // eslint-disable-next-line no-param-reassign report.iouReportAmount = ReportUtils.getIOUTotal(report, iouReports); @@ -252,7 +252,7 @@ function getOptionData(reportID) { result.hasOutstandingIOU = report.hasOutstandingIOU; const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; - const subtitle = ReportUtils.getChatRoomSubtitle(report, policies); + const subtitle = ReportUtils.getChatRoomSubtitle(report); const login = Str.removeSMSDomain(lodashGet(personalDetail, 'login', '')); const formattedLogin = Str.isSMSLogin(login) ? LocalePhoneNumber.formatPhoneNumber(login) : login; @@ -288,7 +288,7 @@ function getOptionData(reportID) { || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { displayName: archiveReason.displayName || report.lastActorEmail, - policyName: ReportUtils.getPolicyName(report, policies), + policyName: ReportUtils.getPolicyName(report), }); } @@ -320,7 +320,7 @@ function getOptionData(reportID) { result.payPalMeAddress = personalDetail.payPalMeAddress; } - const reportName = ReportUtils.getReportName(report, policies); + const reportName = ReportUtils.getReportName(report); result.text = reportName; result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 936f0a0d423b..8dc81875fa6d 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -98,7 +98,7 @@ class ReportDetailsPage extends Component { render() { const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(this.props.report); const isChatRoom = ReportUtils.isChatRoom(this.props.report); - const chatRoomSubtitle = ReportUtils.getChatRoomSubtitle(this.props.report, this.props.policies); + const chatRoomSubtitle = ReportUtils.getChatRoomSubtitle(this.props.report); const participants = lodashGet(this.props.report, 'participants', []); const isMultipleParticipant = participants.length > 1; const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips( @@ -127,7 +127,7 @@ class ReportDetailsPage extends Component { { const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(participantPersonalDetails, isMultipleParticipant); const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); - const title = ReportUtils.getReportName(props.report, props.policies); + const title = ReportUtils.getReportName(props.report); - const subtitle = ReportUtils.getChatRoomSubtitle(props.report, props.policies); + const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); const isAutomatedExpensifyAccount = (participants.length === 1 && ReportUtils.hasAutomatedExpensifyEmails(participants)); const guideCalendarLink = lodashGet(props.account, 'guideCalendarLink'); @@ -83,7 +76,7 @@ const HeaderView = (props) => { const shouldShowCallButton = (isConcierge && guideCalendarLink) || !isAutomatedExpensifyAccount; const avatarTooltip = isChatRoom ? undefined : _.pluck(displayNamesWithTooltips, 'tooltip'); const shouldShowSubscript = isPolicyExpenseChat && !props.report.isOwnPolicyExpenseChat && !ReportUtils.isArchivedRoom(props.report); - const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policies); + const icons = ReportUtils.getIcons(props.report, props.personalDetails); const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; return ( diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index df5ba50e622a..6068e2de9cdc 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -278,7 +278,6 @@ class ReportScreen extends React.Component { onNavigationMenuButtonClicked={() => Navigation.navigate(ROUTES.HOME)} personalDetails={this.props.personalDetails} report={this.props.report} - policies={this.props.policies} /> {Boolean(this.props.accountManagerReportID) && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && ( diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index a47ff6d4de4e..ddb44fd31102 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -70,6 +70,9 @@ const propTypes = { /** Should we display the new marker on top of the comment? */ shouldDisplayNewMarker: PropTypes.bool.isRequired, + /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ + shouldShowSubscriptAvatar: PropTypes.bool, + /** Position index of the report action in the overall report FlatList view */ index: PropTypes.number.isRequired, @@ -90,6 +93,7 @@ const defaultProps = { hasOutstandingIOU: false, preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, personalDetails: {}, + shouldShowSubscriptAvatar: false, }; class ReportActionItem extends Component { @@ -325,6 +329,8 @@ class ReportActionItem extends Component { action={this.props.action} showHeader={!this.props.draftMessage} wrapperStyles={[styles.chatItem, isWhisper ? styles.pt1 : {}]} + shouldShowSubscriptAvatar={this.props.shouldShowSubscriptAvatar} + report={this.props.report} > {this.renderItemContent(hovered || this.state.isContextMenuActive)} diff --git a/src/pages/home/report/ReportActionItemCreated.js b/src/pages/home/report/ReportActionItemCreated.js index f942b9e05139..badc87f3624a 100644 --- a/src/pages/home/report/ReportActionItemCreated.js +++ b/src/pages/home/report/ReportActionItemCreated.js @@ -28,22 +28,15 @@ const propTypes = { /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), - /** The policies which the user has access to and which the report could be tied to */ - policies: PropTypes.shape({ - /** Name of the policy */ - name: PropTypes.string, - }), - ...windowDimensionsPropTypes, }; const defaultProps = { report: {}, personalDetails: {}, - policies: {}, }; const ReportActionItemCreated = (props) => { - const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policies); + const icons = ReportUtils.getIcons(props.report, props.personalDetails); return ( { @@ -80,16 +89,25 @@ const ReportActionItemSingle = (props) => { onPressOut={ControlSelection.unblock} onPress={() => showUserDetails(actorEmail)} > - - - + {props.shouldShowSubscriptAvatar ? ( + - - + ) : ( + + + + )} + {props.showHeader ? ( diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 4af8fd161546..dabc6f3ccb81 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -123,6 +123,7 @@ const ReportActionsList = (props) => { action={reportAction} displayAsGroup={ReportActionsUtils.isConsecutiveActionMadeByPreviousActor(sortedReportActions, index)} shouldDisplayNewMarker={shouldDisplayNewMarker} + shouldShowSubscriptAvatar={ReportUtils.isPolicyExpenseChat(report) && reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU} isMostRecentIOUReportAction={reportAction.reportActionID === mostRecentIOUReportActionID} hasOutstandingIOU={hasOutstandingIOU} index={index} diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index d610b740135f..1ae6f67933ea 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -33,18 +33,20 @@ const policy = { policyID: 1, name: 'Vikings Policy', }; -const policies = { - [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, -}; Onyx.init({keys: ONYXKEYS}); -beforeAll(() => waitForPromisesToResolve() - .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS, participantsPersonalDetails)) - .then(() => Onyx.set(ONYXKEYS.SESSION, {email: currentUserEmail}))); -beforeEach(() => Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.DEFAULT).then(waitForPromisesToResolve)); - describe('ReportUtils', () => { + beforeAll(() => { + Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS]: participantsPersonalDetails, + [ONYXKEYS.SESSION]: {email: currentUserEmail}, + [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, + }); + return waitForPromisesToResolve(); + }); + beforeEach(() => Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.DEFAULT).then(waitForPromisesToResolve)); + describe('getDisplayNamesWithTooltips', () => { test('withSingleParticipantReport', () => { expect(ReportUtils.getDisplayNamesWithTooltips(participantsPersonalDetails, false)).toStrictEqual([ @@ -180,7 +182,7 @@ describe('ReportUtils', () => { policyID: policy.policyID, isOwnPolicyExpenseChat: true, ownerEmail: 'ragnar@vikings.net', - }, policies)).toBe('Vikings Policy'); + })).toBe('Vikings Policy'); }); test('as admin', () => { @@ -189,7 +191,7 @@ describe('ReportUtils', () => { policyID: policy.policyID, isOwnPolicyExpenseChat: false, ownerEmail: 'ragnar@vikings.net', - }, policies)).toBe('Ragnar Lothbrok'); + })).toBe('Ragnar Lothbrok'); }); }); @@ -209,10 +211,10 @@ describe('ReportUtils', () => { isOwnPolicyExpenseChat: true, }; - expect(ReportUtils.getReportName(memberArchivedPolicyExpenseChat, policies)).toBe('Vikings Policy (archived)'); + expect(ReportUtils.getReportName(memberArchivedPolicyExpenseChat)).toBe('Vikings Policy (archived)'); return Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.ES) - .then(() => expect(ReportUtils.getReportName(memberArchivedPolicyExpenseChat, policies)).toBe('Vikings Policy (archivado)')); + .then(() => expect(ReportUtils.getReportName(memberArchivedPolicyExpenseChat)).toBe('Vikings Policy (archivado)')); }); test('as admin', () => {