Skip to content
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
55 changes: 8 additions & 47 deletions src/components/ArchivedReportFooter.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
import lodashGet from 'lodash/get';
import React from 'react';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import CONST from '../CONST';
import Banner from './Banner';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import compose from '../libs/compose';
import personalDetailsPropType from '../pages/personalDetailsPropType';
import ONYXKEYS from '../ONYXKEYS';
import * as ReportUtils from '../libs/ReportUtils';
import reportActionPropTypes from '../pages/home/report/reportActionPropTypes';

const propTypes = {
/** The reason this report was archived */
reportClosedAction: PropTypes.shape({
/** Message attached to the report closed action */
originalMessage: PropTypes.shape({
/** The reason the report was closed */
reason: PropTypes.string.isRequired,

/** (For accountMerged reason only), the email of the previous owner of this report. */
oldLogin: PropTypes.string,

/** (For accountMerged reason only), the email of the account the previous owner was merged into */
newLogin: PropTypes.string,
}).isRequired,
}),

/** The archived report */
report: PropTypes.shape({
/** The policy this report is attached to */
policyID: PropTypes.string,
/** The email of the owner of the report */
ownerEmail: PropTypes.string,
}).isRequired,

/** Array of report actions for this report */
reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)).isRequired,

/** Personal details of all users */
personalDetails: PropTypes.objectOf(personalDetailsPropType).isRequired,

Expand All @@ -44,40 +31,14 @@ const propTypes = {
...withLocalizePropTypes,
};

const defaultProps = {
reportClosedAction: {
originalMessage: {
reason: CONST.REPORT.ARCHIVE_REASON.DEFAULT,
},
},
};

const ArchivedReportFooter = (props) => {
const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT);
let displayName = lodashGet(props.personalDetails, `${props.report.ownerEmail}.displayName`, props.report.ownerEmail);

let oldDisplayName;
if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) {
const newLogin = props.reportClosedAction.originalMessage.newLogin;
const oldLogin = props.reportClosedAction.originalMessage.oldLogin;
displayName = lodashGet(props.personalDetails, `${newLogin}.displayName`, newLogin);
oldDisplayName = lodashGet(props.personalDetails, `${oldLogin}.displayName`, oldLogin);
}

const archivedText = ReportUtils.getArchivedText(props.report, props.reportActions, props.personalDetails, props.policies);
return (
<Banner
text={props.translate(`reportArchiveReasons.${archiveReason}`, {
displayName: `<strong>${displayName}</strong>`,
oldDisplayName: `<strong>${oldDisplayName}</strong>`,
policyName: `<strong>${ReportUtils.getPolicyName(props.report, props.policies)}</strong>`,
})}
shouldRenderHTML={archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT}
/>
<Banner html={archivedText} />
);
};

ArchivedReportFooter.propTypes = propTypes;
ArchivedReportFooter.defaultProps = defaultProps;
ArchivedReportFooter.displayName = 'ArchivedReportFooter';

export default compose(
Expand Down
19 changes: 3 additions & 16 deletions src/components/Banner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@ import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import RenderHTML from './RenderHTML';
import Text from './Text';
import styles from '../styles/styles';
import * as StyleUtils from '../styles/StyleUtils';
import getButtonState from '../libs/getButtonState';

const propTypes = {
/** Text to display in the banner. */
text: PropTypes.string.isRequired,

/** Should this component render the text as HTML? */
shouldRenderHTML: PropTypes.bool,
};

const defaultProps = {
shouldRenderHTML: false,
/** HTML to display in the banner. */
html: PropTypes.string.isRequired,
};

const Banner = props => (
Expand All @@ -39,18 +31,13 @@ const Banner = props => (
fill={StyleUtils.getIconFillColor(getButtonState(isHovered))}
/>
</View>
{
props.shouldRenderHTML
? <RenderHTML html={props.text} />
: <Text>{props.text}</Text>
}
<RenderHTML html={props.html} />
</View>
)}
</Hoverable>
);

Banner.propTypes = propTypes;
Banner.defaultProps = defaultProps;
Banner.displayName = 'Banner';

export default memo(Banner);
51 changes: 31 additions & 20 deletions src/components/ReportWelcomeText.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ONYXKEYS from '../ONYXKEYS';
import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
import Tooltip from './Tooltip';
import RenderHTML from './RenderHTML';

const personalDetailsPropTypes = PropTypes.shape({
/** The login of the person (either email or phone number) */
Expand All @@ -32,7 +33,7 @@ const propTypes = {

/* Onyx Props */

/** All of the personal details for everyone */
/** All the personal details for everyone */
personalDetails: PropTypes.objectOf(personalDetailsPropTypes).isRequired,

/** The policies which the user has access to and which the report could be tied to */
Expand All @@ -52,6 +53,8 @@ const ReportWelcomeText = (props) => {
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report);
const isChatRoom = ReportUtils.isChatRoom(props.report);
const isDefault = !(isChatRoom || isPolicyExpenseChat);
const isArchivedRoom = ReportUtils.isArchivedRoom(props.report);
const reportArchivedText = ReportUtils.getArchivedText(props.report, props.reportActions, props.personalDetails, props.policies);
const participants = lodashGet(props.report, 'participants', []);
const isMultipleParticipant = participants.length > 1;
const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(
Expand All @@ -62,25 +65,29 @@ const ReportWelcomeText = (props) => {
return (
<Text style={[styles.mt3, styles.mw100, styles.textAlignCenter]}>
{isPolicyExpenseChat && (
<>
{/* Add align center style individually because of limited style inheritance in React Native https://reactnative.dev/docs/text#limited-style-inheritance */}
<Text style={styles.textAlignCenter}>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')}
</Text>
<Text style={[styles.textStrong]}>
{/* Use the policyExpenseChat owner's first name or their email if it's undefined or an empty string */}
{lodashGet(props.personalDetails, [props.report.ownerEmail, 'firstName']) || props.report.ownerEmail}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')}
</Text>
<Text style={[styles.textStrong]}>
{ReportUtils.getPolicyName(props.report, props.policies)}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')}
</Text>
</>
isArchivedRoom
? <RenderHTML html={reportArchivedText} />
: (
<>
{/* Add align center style individually because of limited style inheritance in React Native https://reactnative.dev/docs/text#limited-style-inheritance */}
<Text style={styles.textAlignCenter}>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')}
</Text>
<Text style={[styles.textStrong]}>
{/* Use the policyExpenseChat owner's first name or their email if it's undefined or an empty string */}
{lodashGet(props.personalDetails, [props.report.ownerEmail, 'firstName']) || props.report.ownerEmail}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')}
</Text>
<Text style={[styles.textStrong]}>
{ReportUtils.getPolicyName(props.report, props.policies)}
</Text>
<Text>
{props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartThree')}
</Text>
</>
)
)}
{isChatRoom && (
<>
Expand Down Expand Up @@ -136,5 +143,9 @@ export default compose(
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
reportActions: {
key: props => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${props.report.reportID}`,
canEvict: false,
},
}),
)(ReportWelcomeText);
38 changes: 38 additions & 0 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _ from 'underscore';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import lodashFindLast from 'lodash/findLast';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
Expand Down Expand Up @@ -502,6 +503,42 @@ function navigateToDetailsPage(report) {
Navigation.navigate(ROUTES.getReportParticipantsRoute(report.reportID));
}

/**
* Get the text explaining why a report was archived.
*
* @param {Object} report
* @param {Object} reportActions
* @param {Object} personalDetails
* @param {Object} policies
* @returns {String|null}
*/
function getArchivedText(report, reportActions, personalDetails, policies) {
if (!isArchivedRoom(report)) {
return Localize.translateLocal(`reportArchiveReasons.${CONST.REPORT.ARCHIVE_REASON.DEFAULT}`);
}

const reportClosedAction = lodashFindLast(reportActions, action => action.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED);
if (!reportClosedAction) {
return Localize.translateLocal(`reportArchiveReasons.${CONST.REPORT.ARCHIVE_REASON.DEFAULT}`);
}

const archiveReason = lodashGet(reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT);
let displayName = lodashGet(personalDetails, `${report.ownerEmail}.displayName`, report.ownerEmail);
let oldDisplayName;
if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) {
const newLogin = reportClosedAction.originalMessage.newLogin;
const oldLogin = reportClosedAction.originalMessage.oldLogin;
displayName = lodashGet(personalDetails, `${newLogin}.displayName`, newLogin);
oldDisplayName = lodashGet(personalDetails, `${oldLogin}.displayName`, oldLogin);
}

return Localize.translateLocal(`reportArchiveReasons.${archiveReason}`, {
displayName: `<strong>${displayName}</strong>`,
oldDisplayName: `<strong>${oldDisplayName}</strong>`,
policyName: `<strong>${getPolicyName(report, policies)}</strong>`,
});
}

export {
getReportParticipantsTitle,
isReportMessageAttachment,
Expand Down Expand Up @@ -529,4 +566,5 @@ export {
getDisplayNamesWithTooltips,
getReportName,
navigateToDetailsPage,
getArchivedText,
};
9 changes: 1 addition & 8 deletions src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import {Keyboard, View} from 'react-native';
import _ from 'underscore';
import lodashFindLast from 'lodash/findLast';
import styles from '../../styles/styles';
import ScreenWrapper from '../../components/ScreenWrapper';
import HeaderView from './HeaderView';
Expand Down Expand Up @@ -165,13 +164,7 @@ class ReportScreen extends React.Component {
}

const reportID = getReportID(this.props.route);

const isArchivedRoom = ReportUtils.isArchivedRoom(this.props.report);
let reportClosedAction;
if (isArchivedRoom) {
reportClosedAction = lodashFindLast(this.props.reportActions, action => action.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED);
}

return (
<ScreenWrapper style={[styles.appContent, styles.flex1]}>
<HeaderView
Expand All @@ -198,8 +191,8 @@ class ReportScreen extends React.Component {
isArchivedRoom
? (
<ArchivedReportFooter
reportClosedAction={reportClosedAction}
report={this.props.report}
reportActions={this.props.reportActions}
/>
) : (
<SwipeableView onSwipeDown={Keyboard.dismiss}>
Expand Down
5 changes: 2 additions & 3 deletions src/stories/Banner.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ const Template = args => <Banner {...args} />;
// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
const InfoBanner = Template.bind({});
InfoBanner.args = {
text: 'This is an informational banner',
html: 'This is an informational banner',
};

const HTMLBanner = Template.bind({});
HTMLBanner.args = {
text: 'This is a informational banner containing <strong><em>HTML</em></strong>',
shouldRenderHTML: true,
html: 'This is a informational banner containing <strong><em>HTML</em></strong>',
};

export default story;
Expand Down