diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js
index 81eace444de4..03ae8f51bfb6 100644
--- a/src/components/AvatarWithDisplayName.js
+++ b/src/components/AvatarWithDisplayName.js
@@ -43,6 +43,8 @@ const propTypes = {
/** Whether if it's an unauthenticated user */
isAnonymous: PropTypes.bool,
+ shouldEnableDetailPageNavigation: PropTypes.bool,
+
...windowDimensionsPropTypes,
...withLocalizePropTypes,
};
@@ -53,9 +55,15 @@ const defaultProps = {
report: {},
isAnonymous: false,
size: CONST.AVATAR_SIZE.DEFAULT,
+ shouldEnableDetailPageNavigation: false,
};
-const showActorDetails = (report) => {
+const showActorDetails = (report, shouldEnableDetailPageNavigation = false) => {
+ // We should navigate to the details page if the report is a IOU/expense report
+ if (shouldEnableDetailPageNavigation) {
+ return ReportUtils.navigateToDetailsPage(report);
+ }
+
if (ReportUtils.isExpenseReport(report)) {
Navigation.navigate(ROUTES.PROFILE.getRoute(report.ownerAccountID));
return;
@@ -93,12 +101,12 @@ function AvatarWithDisplayName(props) {
const defaultSubscriptSize = isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : props.size;
const avatarBorderColor = props.isAnonymous ? themeColors.highlightBG : themeColors.componentBG;
- return (
+ const headerView = (
{Boolean(props.report && title) && (
showActorDetails(props.report)}
+ onPress={() => showActorDetails(props.report, props.shouldEnableDetailPageNavigation)}
accessibilityLabel={title}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
@@ -145,6 +153,21 @@ function AvatarWithDisplayName(props) {
)}
);
+
+ if (!props.shouldEnableDetailPageNavigation) {
+ return headerView;
+ }
+
+ return (
+ ReportUtils.navigateToDetailsPage(props.report)}
+ style={[styles.flexRow, styles.alignItemsCenter, styles.flex1]}
+ accessibilityLabel={title}
+ accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
+ >
+ {headerView}
+
+ );
}
AvatarWithDisplayName.propTypes = propTypes;
AvatarWithDisplayName.displayName = 'AvatarWithDisplayName';
diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js
index c720529371d7..e138876c39dc 100755
--- a/src/components/HeaderWithBackButton/index.js
+++ b/src/components/HeaderWithBackButton/index.js
@@ -46,6 +46,7 @@ function HeaderWithBackButton({
horizontal: 0,
},
threeDotsMenuItems = [],
+ shouldEnableDetailPageNavigation = false,
children = null,
onModalHide = () => {},
shouldOverlay = false,
@@ -76,14 +77,14 @@ function HeaderWithBackButton({
)}
- {shouldShowAvatarWithDisplay && (
+ {shouldShowAvatarWithDisplay ? (
- )}
- {!shouldShowAvatarWithDisplay && (
+ ) : (
avatarSizeToStylesMap[props.size] || avatarSizeToStylesMap.default, [props.size]);
+
const tooltipTexts = props.shouldShowTooltip ? _.pluck(props.icons, 'name') : [''];
+ const avatarSize = useMemo(() => {
+ if (props.isFocusMode) {
+ return CONST.AVATAR_SIZE.MID_SUBSCRIPT;
+ }
+
+ if (props.size === CONST.AVATAR_SIZE.LARGE) {
+ return CONST.AVATAR_SIZE.MEDIUM;
+ }
+
+ return CONST.AVATAR_SIZE.SMALLER;
+ }, [props.isFocusMode, props.size]);
const avatarRows = useMemo(() => {
// If we're not displaying avatars in rows or the number of icons is less than or equal to the max avatars in a row, return a single row
@@ -247,7 +276,7 @@ function MultipleAvatars(props) {
-
+
{props.icons.length === 2 ? (
ReportUtils.isChatThread(props.report), [props.report]);
const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(props.report), [props.report]);
const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(props.report), [props.report]);
+ const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(props.report), [props.report]);
// eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx
const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]);
+ const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report);
const canLeaveRoom = useMemo(() => ReportUtils.canLeaveRoom(props.report, !_.isEmpty(policy)), [policy, props.report]);
- const participants = useMemo(() => lodashGet(props.report, 'participantAccountIDs', []), [props.report]);
+ const participants = useMemo(() => ReportUtils.getParticipantsIDs(props.report), [props.report]);
const menuItems = useMemo(() => {
const items = [
@@ -113,7 +116,7 @@ function ReportDetailsPage(props) {
}
// Prevent displaying private notes option for threads and task reports
- if (!isThread && !ReportUtils.isTaskReport(props.report)) {
+ if (!isThread && !isMoneyRequestReport && !ReportUtils.isTaskReport(props.report)) {
items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.PRIVATE_NOTES,
translationKey: 'privateNotes.title',
@@ -135,13 +138,15 @@ function ReportDetailsPage(props) {
}
return items;
- }, [props.report, participants, isArchivedRoom, shouldDisableSettings, isThread, isUserCreatedPolicyRoom, canLeaveRoom]);
+ }, [isArchivedRoom, participants.length, shouldDisableSettings, isThread, isMoneyRequestReport, props.report, isUserCreatedPolicyRoom, canLeaveRoom]);
const displayNamesWithTooltips = useMemo(() => {
const hasMultipleParticipants = participants.length > 1;
return ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails), hasMultipleParticipants);
}, [participants, props.personalDetails]);
+ const icons = useMemo(() => ReportUtils.getIcons(props.report, props.personalDetails, props.policies), [props.report, props.personalDetails, props.policies]);
+
const chatRoomSubtitleText = chatRoomSubtitle ? (
-
+ {isMoneyRequestReport ? (
+
+ ) : (
+
+ )}
@@ -185,6 +197,13 @@ function ReportDetailsPage(props) {
) : (
chatRoomSubtitleText
)}
+ {!_.isEmpty(parentNavigationSubtitleData) && isMoneyRequestReport && (
+
+ )}
{_.map(menuItems, (item) => {
diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js
index 7f453d16817b..67933ebfe3e4 100755
--- a/src/pages/ReportParticipantsPage.js
+++ b/src/pages/ReportParticipantsPage.js
@@ -54,17 +54,8 @@ const defaultProps = {
* @param {Object} translate The localize
* @return {Array}
*/
-const getAllParticipants = (report, personalDetails, translate) => {
- let participantAccountIDs = report.participantAccountIDs;
-
- // Build participants list for IOU report - there is a possibility that participantAccountIDs may be undefined/empty
- if (ReportUtils.isIOUReport(report)) {
- const managerID = report.managerID || '';
- const ownerAccountID = report.ownerAccountID || '';
- participantAccountIDs = [managerID, ownerAccountID];
- }
-
- return _.chain(participantAccountIDs)
+const getAllParticipants = (report, personalDetails, translate) =>
+ _.chain(ReportUtils.getParticipantsIDs(report))
.map((accountID, index) => {
const userPersonalDetail = lodashGet(personalDetails, accountID, {displayName: personalDetails.displayName || translate('common.hidden'), avatar: ''});
const userLogin = LocalePhoneNumber.formatPhoneNumber(userPersonalDetail.login || '') || translate('common.hidden');
@@ -90,7 +81,6 @@ const getAllParticipants = (report, personalDetails, translate) => {
})
.sortBy((participant) => participant.displayName.toLowerCase())
.value();
-};
function ReportParticipantsPage(props) {
const participants = _.map(getAllParticipants(props.report, props.personalDetails, props.translate), (participant) => ({
@@ -110,7 +100,8 @@ function ReportParticipantsPage(props) {
ReportUtils.isChatRoom(props.report) ||
ReportUtils.isPolicyExpenseChat(props.report) ||
ReportUtils.isChatThread(props.report) ||
- ReportUtils.isTaskReport(props.report)
+ ReportUtils.isTaskReport(props.report) ||
+ ReportUtils.isMoneyRequestReport(props.report)
? 'common.members'
: 'common.details',
)}
diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js
index 75bf5fd24f1d..e6d36ebc7070 100644
--- a/src/pages/ShareCodePage.js
+++ b/src/pages/ShareCodePage.js
@@ -1,5 +1,6 @@
import React from 'react';
import {View, ScrollView} from 'react-native';
+import _ from 'underscore';
import ScreenWrapper from '../components/ScreenWrapper';
import HeaderWithBackButton from '../components/HeaderWithBackButton';
import Navigation from '../libs/Navigation/Navigation';
@@ -40,11 +41,30 @@ const defaultProps = {
class ShareCodePage extends React.Component {
qrCodeRef = React.createRef();
+ /**
+ * @param {Boolean} isReport
+ * @return {String|string|*}
+ */
+ getSubtitle(isReport) {
+ if (ReportUtils.isExpenseReport(this.props.report)) {
+ return ReportUtils.getPolicyName(this.props.report);
+ }
+ if (ReportUtils.isMoneyRequestReport(this.props.report)) {
+ // generate subtitle from participants
+ return _.map(ReportUtils.getParticipantsIDs(this.props.report), (accountID) => ReportUtils.getDisplayNameForParticipant(accountID)).join(' & ');
+ }
+
+ if (isReport) {
+ return ReportUtils.getParentNavigationSubtitle(this.props.report).workspaceName || ReportUtils.getChatRoomSubtitle(this.props.report);
+ }
+
+ return this.props.formatPhoneNumber(this.props.session.email);
+ }
+
render() {
const isReport = this.props.report != null && this.props.report.reportID != null;
const title = isReport ? ReportUtils.getReportName(this.props.report) : this.props.currentUserPersonalDetails.displayName;
- const formattedEmail = this.props.formatPhoneNumber(this.props.session.email);
- const subtitle = isReport ? ReportUtils.getParentNavigationSubtitle(this.props.report).workspaceName || ReportUtils.getChatRoomSubtitle(this.props.report) : formattedEmail;
+ const subtitle = this.getSubtitle(isReport);
const urlWithTrailingSlash = Url.addTrailingForwardSlash(this.props.environmentURL);
const url = isReport
? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(this.props.report.reportID)}`
diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.js
index 3db6bef16e30..9f4f4d048354 100644
--- a/src/pages/settings/Report/ReportSettingsPage.js
+++ b/src/pages/settings/Report/ReportSettingsPage.js
@@ -58,10 +58,11 @@ function ReportSettingsPage(props) {
// The workspace the report is on, null if the user isn't a member of the workspace
const linkedWorkspace = useMemo(() => _.find(policies, (policy) => policy && policy.id === report.policyID), [policies, report.policyID]);
const shouldDisableRename = useMemo(() => ReportUtils.shouldDisableRename(report, linkedWorkspace), [report, linkedWorkspace]);
+ const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
// We only want policy owners and admins to be able to modify the welcome message.
const shouldDisableWelcomeMessage =
- ReportUtils.isArchivedRoom(report) || !ReportUtils.isChatRoom(report) || _.isEmpty(linkedWorkspace) || linkedWorkspace.role !== CONST.POLICY.ROLE.ADMIN;
+ isMoneyRequestReport || ReportUtils.isArchivedRoom(report) || !ReportUtils.isChatRoom(report) || _.isEmpty(linkedWorkspace) || linkedWorkspace.role !== CONST.POLICY.ROLE.ADMIN;
const shouldDisableSettings = _.isEmpty(report) || ReportUtils.shouldDisableSettings(report) || ReportUtils.isArchivedRoom(report);
const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report);
@@ -72,7 +73,13 @@ function ReportSettingsPage(props) {
const writeCapability = ReportUtils.isAdminRoom(report) ? CONST.REPORT.WRITE_CAPABILITIES.ADMINS : report.writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL;
const writeCapabilityText = translate(`writeCapabilityPage.writeCapability.${writeCapability}`);
- const shouldAllowWriteCapabilityEditing = lodashGet(linkedWorkspace, 'role', '') === CONST.POLICY.ROLE.ADMIN && !ReportUtils.isAdminRoom(report);
+ const shouldAllowWriteCapabilityEditing = lodashGet(linkedWorkspace, 'role', '') === CONST.POLICY.ROLE.ADMIN && !ReportUtils.isAdminRoom(report) && !isMoneyRequestReport;
+
+ const shouldShowNotificationPref = !isMoneyRequestReport && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ const roomNameLabel = translate(isMoneyRequestReport ? 'workspace.editor.nameInputLabel' : 'newRoomPage.roomName');
+ const reportName = ReportUtils.getReportName(props.report);
+
+ const shouldShowWriteCapability = !isMoneyRequestReport;
return (
@@ -82,7 +89,7 @@ function ReportSettingsPage(props) {
onBackButtonPress={() => Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID))}
/>
- {report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && (
+ {shouldShowNotificationPref && (
- {translate('newRoomPage.roomName')}
+ {roomNameLabel}
- {report.reportName}
+ {reportName}
) : (
@@ -122,29 +129,30 @@ function ReportSettingsPage(props) {
)}
)}
- {shouldAllowWriteCapabilityEditing ? (
- Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(report.reportID))}
- />
- ) : (
-
-
- {translate('writeCapabilityPage.label')}
-
-
- {writeCapabilityText}
-
-
- )}
+ {shouldShowWriteCapability &&
+ (shouldAllowWriteCapabilityEditing ? (
+ Navigation.navigate(ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.getRoute(report.reportID))}
+ />
+ ) : (
+
+
+ {translate('writeCapabilityPage.label')}
+
+
+ {writeCapabilityText}
+
+
+ ))}
{Boolean(linkedWorkspace) && (
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 7bba63c8f09f..563f075e0f91 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1855,6 +1855,13 @@ const styles = (theme) => ({
borderRadius: 18,
},
+ singleAvatarMedium: {
+ height: 52,
+ width: 52,
+ backgroundColor: theme.icon,
+ borderRadius: 52,
+ },
+
secondAvatar: {
position: 'absolute',
right: -18,
@@ -1873,6 +1880,15 @@ const styles = (theme) => ({
borderColor: 'transparent',
},
+ secondAvatarMedium: {
+ position: 'absolute',
+ right: -36,
+ bottom: -36,
+ borderWidth: 3,
+ borderRadius: 52,
+ borderColor: 'transparent',
+ },
+
secondAvatarSubscript: {
position: 'absolute',
right: -6,