diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index 0d77fc437c79..713dfa3df45a 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -5,6 +5,9 @@ export default {
// Holds information about the users account that is logging in
ACCOUNT: 'account',
+ // Holds the reportID for the report between the user and their account manager
+ ACCOUNT_MANAGER_REPORT_ID: 'accountManagerReportID',
+
// Boolean flag only true when first set
NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'isFirstTimeNewExpensifyUser',
diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js
index 1b6958fc2e65..c271b0f8c0bc 100644
--- a/src/components/ArchivedReportFooter.js
+++ b/src/components/ArchivedReportFooter.js
@@ -70,6 +70,7 @@ const ArchivedReportFooter = (props) => {
policyName: `${ReportUtils.getPolicyName(props.report, props.policies)}`,
})}
shouldRenderHTML={archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT}
+ shouldShowIcon
/>
);
};
diff --git a/src/components/Banner.js b/src/components/Banner.js
index 87808c22af24..3b5a8d66e3aa 100644
--- a/src/components/Banner.js
+++ b/src/components/Banner.js
@@ -1,6 +1,7 @@
import React, {memo} from 'react';
import PropTypes from 'prop-types';
-import {View} from 'react-native';
+import {View, Pressable} from 'react-native';
+import compose from '../libs/compose';
import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
@@ -9,17 +10,45 @@ import Text from './Text';
import styles from '../styles/styles';
import * as StyleUtils from '../styles/StyleUtils';
import getButtonState from '../libs/getButtonState';
+import Tooltip from './Tooltip';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Text to display in the banner. */
text: PropTypes.string.isRequired,
+ /** Should this component render the left-aligned exclamation icon? */
+ shouldShowIcon: PropTypes.bool,
+
+ /** Should this component render a close button? */
+ shouldShowCloseButton: PropTypes.bool,
+
/** Should this component render the text as HTML? */
shouldRenderHTML: PropTypes.bool,
+
+ /** Callback called when the close button is pressed */
+ onClose: PropTypes.func,
+
+ /** Callback called when the message is pressed */
+ onPress: PropTypes.func,
+
+ // eslint-disable-next-line react/forbid-prop-types
+ containerStyles: PropTypes.arrayOf(PropTypes.object),
+
+ // eslint-disable-next-line react/forbid-prop-types
+ textStyles: PropTypes.arrayOf(PropTypes.object),
+
+ ...withLocalizePropTypes,
};
const defaultProps = {
shouldRenderHTML: false,
+ shouldShowIcon: false,
+ shouldShowCloseButton: false,
+ onClose: () => {},
+ onPress: () => {},
+ containerStyles: [],
+ textStyles: [],
};
const Banner = props => (
@@ -32,19 +61,35 @@ const Banner = props => (
styles.borderRadiusNormal,
isHovered ? styles.activeComponentBG : styles.hoveredComponentBG,
styles.breakAll,
+ ...props.containerStyles,
]}
>
-
-
+
+ {props.shouldShowIcon && (
+
+
+
+ )}
+ {
+ props.shouldRenderHTML
+ ?
+ : {props.text}
+ }
- {
- props.shouldRenderHTML
- ?
- : {props.text}
- }
+ {props.shouldShowCloseButton && (
+
+
+
+
+
+ )}
)}
@@ -54,4 +99,7 @@ Banner.propTypes = propTypes;
Banner.defaultProps = defaultProps;
Banner.displayName = 'Banner';
-export default memo(Banner);
+export default compose(
+ withLocalize,
+ memo,
+)(Banner);
diff --git a/src/languages/en.js b/src/languages/en.js
index 0c01680f2c8e..1b7e384a92dd 100755
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -211,6 +211,7 @@ export default {
beginningOfChatHistoryPolicyExpenseChatPartOne: 'Collaboration between ',
beginningOfChatHistoryPolicyExpenseChatPartTwo: ' and ',
beginningOfChatHistoryPolicyExpenseChatPartThree: ' starts here! š This is the place to chat, request money and settle up.',
+ chatWithAccountManager: 'Chat with your account manager here',
},
newMessages: 'New messages',
reportTypingIndicator: {
diff --git a/src/languages/es.js b/src/languages/es.js
index 5fcaca9d0ee5..9fee9c421a5a 100644
--- a/src/languages/es.js
+++ b/src/languages/es.js
@@ -211,6 +211,7 @@ export default {
beginningOfChatHistoryPolicyExpenseChatPartOne: 'Ā”La colaboraciĆ³n entre ',
beginningOfChatHistoryPolicyExpenseChatPartTwo: ' y ',
beginningOfChatHistoryPolicyExpenseChatPartThree: ' empieza aquĆ! :tada: Este es el lugar donde chatear, pedir dinero y pagar.',
+ chatWithAccountManager: 'Chatea con tu gestor de cuenta aquĆ',
},
newMessages: 'Mensajes nuevos',
reportTypingIndicator: {
diff --git a/src/libs/Navigation/DeprecatedCustomActions.js b/src/libs/Navigation/DeprecatedCustomActions.js
index 1c192d60f93e..eb10d9c2f827 100644
--- a/src/libs/Navigation/DeprecatedCustomActions.js
+++ b/src/libs/Navigation/DeprecatedCustomActions.js
@@ -102,16 +102,23 @@ function pushDrawerRoute(route) {
const screenRoute = {type: 'route', name: newScreenName};
const history = _.map(state.history ? [...state.history] : [screenRoute], () => screenRoute);
- // Force drawer to close
- // https://github.com/react-navigation/react-navigation/blob/94ab791cae5061455f036cd3f6bc7fa63167e7c7/packages/routers/src/DrawerRouter.tsx#L142
- const hasDrawerhistory = _.find(state.history || [], h => h.type === 'drawer');
- if (!hasDrawerhistory || currentState.type !== 'drawer') {
+ const drawerHistoryItem = _.find(state.history || [], h => h.type === 'drawer');
+ const isDrawerClosed = drawerHistoryItem && drawerHistoryItem.status === 'closed';
+ if (!drawerHistoryItem || currentState.type !== 'drawer') {
+ // Add the drawer item to the navigation history to control if the drawer should be in open or closed state
history.push({
type: 'drawer',
- // If current state is not from drawer navigator then always use closed status to close the drawer
+ // If current state is not from drawer navigator then always force the drawer to close by using closed status
+ // https://github.com/react-navigation/react-navigation/blob/94ab791cae5061455f036cd3f6bc7fa63167e7c7/packages/routers/src/DrawerRouter.tsx#L142
status: currentState.type !== 'drawer' || currentState.default === 'open' ? 'closed' : 'open',
});
+ } else if (isDrawerClosed) {
+ // Keep the drawer closed if it's already closed
+ history.push({
+ type: 'drawer',
+ status: 'closed',
+ });
}
return CommonActions.reset({
diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js
index 2107b4eb5ed1..b76237b06b3a 100644
--- a/src/pages/home/ReportScreen.js
+++ b/src/pages/home/ReportScreen.js
@@ -30,6 +30,8 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/
import OfflineIndicator from '../../components/OfflineIndicator';
import OfflineWithFeedback from '../../components/OfflineWithFeedback';
import withDrawerState, {withDrawerPropTypes} from '../../components/withDrawerState';
+import Banner from '../../components/Banner';
+import withLocalize from '../../components/withLocalize';
import reportPropTypes from '../reportPropTypes';
const propTypes = {
@@ -112,11 +114,14 @@ class ReportScreen extends React.Component {
this.onSubmitComment = this.onSubmitComment.bind(this);
this.updateViewportOffsetTop = this.updateViewportOffsetTop.bind(this);
+ this.chatWithAccountManager = this.chatWithAccountManager.bind(this);
+ this.dismissBanner = this.dismissBanner.bind(this);
this.removeViewportResizeListener = () => {};
this.state = {
skeletonViewContainerHeight: 0,
viewportOffsetTop: 0,
+ isBannerVisible: true,
};
}
@@ -191,6 +196,14 @@ class ReportScreen extends React.Component {
this.setState({viewportOffsetTop});
}
+ dismissBanner() {
+ this.setState({isBannerVisible: false});
+ }
+
+ chatWithAccountManager() {
+ Navigation.navigate(ROUTES.getReportRoute(this.props.accountManagerReportID));
+ }
+
render() {
if (!this.props.isSidebarLoaded) {
return null;
@@ -236,6 +249,16 @@ class ReportScreen extends React.Component {
onNavigationMenuButtonClicked={() => Navigation.navigate(ROUTES.HOME)}
/>
+ {this.props.accountManagerReportID && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && (
+
+ )}