diff --git a/src/CONST.ts b/src/CONST.ts index 8c437a9f47cc..93576e0ccf9d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1342,6 +1342,7 @@ const CONST = { SETTINGS: 'settings', LEAVE_ROOM: 'leaveRoom', WELCOME_MESSAGE: 'welcomeMessage', + PRIVATE_NOTES: 'privateNotes', }, EDIT_REQUEST_FIELD: { AMOUNT: 'amount', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 2e0b75910bae..80afc4d5ffee 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -290,6 +290,7 @@ const ONYXKEYS = { SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm', SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm', SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm', + PRIVATE_NOTES_FORM: 'privateNotesForm', I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm', INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm', }, diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 36260058e741..9459708c893b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -173,6 +173,14 @@ export default { GOOGLE_SIGN_IN: 'sign-in-with-google', DESKTOP_SIGN_IN_REDIRECT: 'desktop-signin-redirect', + // Routes related to private notes added to the report + PRIVATE_NOTES_VIEW: 'r/:reportID/notes/:accountID', + getPrivateNotesViewRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}`, + PRIVATE_NOTES_LIST: 'r/:reportID/notes', + getPrivateNotesListRoute: (reportID: string) => `r/${reportID}/notes`, + PRIVATE_NOTES_EDIT: 'r/:reportID/notes/:accountID/edit', + getPrivateNotesEditRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit`, + // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. ENABLE_PAYMENTS: 'enable-payments', diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js index c39c1d503258..4f654df2a7b2 100644 --- a/src/components/MenuItem.js +++ b/src/components/MenuItem.js @@ -23,6 +23,7 @@ import variables from '../styles/variables'; import * as Session from '../libs/actions/Session'; import Hoverable from './Hoverable'; import useWindowDimensions from '../hooks/useWindowDimensions'; +import RenderHTML from './RenderHTML'; const propTypes = menuItemPropTypes; @@ -73,6 +74,7 @@ const defaultProps = { title: '', numberOfLinesTitle: 1, shouldGreyOutWhenDisabled: true, + shouldRenderAsHTML: false, }; const MenuItem = React.forwardRef((props, ref) => { @@ -220,7 +222,9 @@ const MenuItem = React.forwardRef((props, ref) => { )} - {Boolean(props.title) && ( + {Boolean(props.title) && Boolean(props.shouldRenderAsHTML) && } + + {Boolean(props.title) && !props.shouldRenderAsHTML && ( { + const PrivateNotesPage = require('../../../pages/PrivateNotes/PrivateNotesViewPage').default; + return PrivateNotesPage; + }, + name: 'PrivateNotes_View', + }, + { + getComponent: () => { + const PrivateNotesListPage = require('../../../pages/PrivateNotes/PrivateNotesListPage').default; + return PrivateNotesListPage; + }, + name: 'PrivateNotes_List', + }, + { + getComponent: () => { + const PrivateNotesEditPage = require('../../../pages/PrivateNotes/PrivateNotesEditPage').default; + return PrivateNotesEditPage; + }, + name: 'PrivateNotes_Edit', + }, +]); + const SignInModalStackNavigator = createModalStackNavigator([ { getComponent: () => { @@ -790,6 +814,7 @@ export { WalletStatementStackNavigator, FlagCommentStackNavigator, EditRequestStackNavigator, + PrivateNotesModalStackNavigator, NewTeachersUniteNavigator, SignInModalStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js index 1340c4bb8e62..27a15fa3d763 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js @@ -108,6 +108,10 @@ function RightModalNavigator(props) { name="SignIn" component={ModalStackNavigators.SignInModalStackNavigator} /> + diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 3311fc81bc82..14ee2b895831 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -213,6 +213,13 @@ export default { }, }, }, + Private_Notes: { + screens: { + PrivateNotes_View: ROUTES.PRIVATE_NOTES_VIEW, + PrivateNotes_List: ROUTES.PRIVATE_NOTES_LIST, + PrivateNotes_Edit: ROUTES.PRIVATE_NOTES_EDIT, + }, + }, Report_Details: { screens: { Report_Details_Root: ROUTES.REPORT_WITH_ID_DETAILS, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 2961784d5825..5cf0e51279a9 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1933,6 +1933,136 @@ function flagComment(reportID, reportAction, severity) { API.write('FlagComment', parameters, {optimisticData, successData, failureData}); } +/** + * Updates a given user's private notes on a report + * + * @param {String} reportID + * @param {Number} accountID + * @param {String} note + */ +const updatePrivateNotes = (reportID, accountID, note) => { + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + privateNotes: { + [accountID]: { + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + errors: null, + note, + }, + }, + }, + }, + ]; + + const successData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + privateNotes: { + [accountID]: { + pendingAction: null, + errors: null, + }, + }, + }, + }, + ]; + + const failureData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + privateNotes: { + [accountID]: { + errors: ErrorUtils.getMicroSecondOnyxError("Private notes couldn't be saved"), + }, + }, + }, + }, + ]; + + API.write( + 'UpdateReportPrivateNote', + { + reportID, + privateNotes: note, + }, + {optimisticData, successData, failureData}, + ); +}; + +/** + * Fetches all the private notes for a given report + * + * @param {String} reportID + */ +function getReportPrivateNote(reportID) { + if (_.isEmpty(reportID)) { + return; + } + API.read( + 'GetReportPrivateNote', + { + reportID, + }, + { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + isLoadingPrivateNotes: true, + }, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + isLoadingPrivateNotes: false, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + isLoadingPrivateNotes: false, + }, + }, + ], + }, + ); +} + +/** + * Checks if there are any errors in the private notes for a given report + * + * @param {Object} report + * @returns {Boolean} Returns true if there are errors in any of the private notes on the report + */ +function hasErrorInPrivateNotes(report) { + const privateNotes = lodashGet(report, 'privateNotes', {}); + return _.some(privateNotes, (privateNote) => !_.isEmpty(privateNote.errors)); +} + +/** + * Clears all errors associated with a given private note + * + * @param {String} reportID + * @param {Number} accountID + */ +function clearPrivateNotesError(reportID, accountID) { + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {privateNotes: {[accountID]: {errors: null}}}); +} + export { addComment, addAttachment, @@ -1980,4 +2110,8 @@ export { setLastOpenedPublicRoom, flagComment, openLastOpenedPublicRoom, + updatePrivateNotes, + getReportPrivateNote, + clearPrivateNotesError, + hasErrorInPrivateNotes, }; diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js new file mode 100644 index 000000000000..4cada83941ac --- /dev/null +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js @@ -0,0 +1,158 @@ +import React, {useState, useRef} from 'react'; +import PropTypes from 'prop-types'; +import {View, Keyboard} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; +import Str from 'expensify-common/lib/str'; +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; +import _ from 'underscore'; +import withLocalize from '../../components/withLocalize'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import HeaderWithBackButton from '../../components/HeaderWithBackButton'; +import Navigation from '../../libs/Navigation/Navigation'; +import styles from '../../styles/styles'; +import compose from '../../libs/compose'; +import ONYXKEYS from '../../ONYXKEYS'; +import TextInput from '../../components/TextInput'; +import CONST from '../../CONST'; +import Text from '../../components/Text'; +import Form from '../../components/Form'; +import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; +import reportPropTypes from '../reportPropTypes'; +import personalDetailsPropType from '../personalDetailsPropType'; +import * as Report from '../../libs/actions/Report'; +import useLocalize from '../../hooks/useLocalize'; +import OfflineWithFeedback from '../../components/OfflineWithFeedback'; +import focusAndUpdateMultilineInputRange from '../../libs/focusAndUpdateMultilineInputRange'; + +const propTypes = { + /** All of the personal details for everyone */ + personalDetailsList: PropTypes.objectOf(personalDetailsPropType), + + /** The report currently being looked at */ + report: reportPropTypes, + route: PropTypes.shape({ + /** Params from the URL path */ + params: PropTypes.shape({ + /** reportID and accountID passed via route: /r/:reportID/notes */ + reportID: PropTypes.string, + accountID: PropTypes.string, + }), + }).isRequired, + + /** Session of currently logged in user */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), +}; + +const defaultProps = { + report: {}, + session: { + accountID: null, + }, + personalDetailsList: {}, +}; + +function PrivateNotesEditPage({route, personalDetailsList, session, report}) { + const {translate} = useLocalize(); + + // We need to edit the note in markdown format, but display it in HTML format + const parser = new ExpensiMark(); + const [privateNote, setPrivateNote] = useState(parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim()); + const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID); + + // To focus on the input field when the page loads + const privateNotesInput = useRef(null); + + const savePrivateNote = () => { + const editedNote = parser.replace(privateNote); + Report.updatePrivateNotes(report.reportID, route.params.accountID, editedNote); + Keyboard.dismiss(); + + // Take user back to the PrivateNotesView page + Navigation.goBack(); + }; + + return ( + focusAndUpdateMultilineInputRange(privateNotesInput.current)} + > + Navigation.goBack()} + > + Navigation.dismissModal()} + onBackButtonPress={() => Navigation.goBack()} + /> + + + + {translate( + Str.extractEmailDomain(lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')) === CONST.EMAIL.GUIDES_DOMAIN + ? 'privateNotes.sharedNoteMessage' + : 'privateNotes.personalNoteMessage', + )} + + +
+ Report.clearPrivateNotesError(report.reportID, route.params.accountID)} + style={[styles.mb3]} + > + setPrivateNote(text)} + ref={(el) => (privateNotesInput.current = el)} + /> + +
+
+
+
+ ); +} + +PrivateNotesEditPage.displayName = 'PrivateNotesEditPage'; +PrivateNotesEditPage.propTypes = propTypes; +PrivateNotesEditPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`, + }, + session: { + key: ONYXKEYS.SESSION, + }, + personalDetailsList: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + }), +)(PrivateNotesEditPage); diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.js b/src/pages/PrivateNotes/PrivateNotesListPage.js new file mode 100644 index 000000000000..5ea081a12f25 --- /dev/null +++ b/src/pages/PrivateNotes/PrivateNotesListPage.js @@ -0,0 +1,158 @@ +import React, {useMemo, useEffect} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import _ from 'underscore'; +import lodashGet from 'lodash/get'; +import Navigation from '../../libs/Navigation/Navigation'; +import ONYXKEYS from '../../ONYXKEYS'; +import CONST from '../../CONST'; +import styles from '../../styles/styles'; +import compose from '../../libs/compose'; +import OfflineWithFeedback from '../../components/OfflineWithFeedback'; +import MenuItem from '../../components/MenuItem'; +import useLocalize from '../../hooks/useLocalize'; +import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; +import * as Report from '../../libs/actions/Report'; +import personalDetailsPropType from '../personalDetailsPropType'; +import * as UserUtils from '../../libs/UserUtils'; +import reportPropTypes from '../reportPropTypes'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '../../components/HeaderWithBackButton'; +import {withNetwork} from '../../components/OnyxProvider'; +import networkPropTypes from '../../components/networkPropTypes'; +import ROUTES from '../../ROUTES'; + +const propTypes = { + /** The report currently being looked at */ + report: reportPropTypes, + route: PropTypes.shape({ + /** Params from the URL path */ + params: PropTypes.shape({ + /** reportID and accountID passed via route: /r/:reportID/notes */ + reportID: PropTypes.string, + accountID: PropTypes.string, + }), + }).isRequired, + + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), + + /** All of the personal details for everyone */ + personalDetailsList: PropTypes.objectOf(personalDetailsPropType), + + /** Information about the network */ + network: networkPropTypes.isRequired, + ...withLocalizePropTypes, +}; + +const defaultProps = { + report: {}, + session: { + accountID: null, + }, + personalDetailsList: {}, +}; + +function PrivateNotesListPage({report, personalDetailsList, network, session}) { + const {translate} = useLocalize(); + + useEffect(() => { + if (network.isOffline) { + return; + } + Report.getReportPrivateNote(report.reportID); + }, [report.reportID, network.isOffline]); + + /** + * Gets the menu item for each workspace + * + * @param {Object} item + * @param {Number} index + * @returns {JSX} + */ + function getMenuItem(item, index) { + const keyTitle = item.translationKey ? translate(item.translationKey) : item.title; + + return ( + + + + ); + } + + /** + * Returns a list of private notes on the given chat report + * @returns {Array} the menu item list + */ + const privateNotes = useMemo(() => { + const privateNoteBrickRoadIndicator = (accountID) => (!_.isEmpty(lodashGet(report, ['privateNotes', accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''); + return _.chain(lodashGet(report, 'privateNotes', {})) + .map((privateNote, accountID) => ({ + title: Number(lodashGet(session, 'accountID', null)) === Number(accountID) ? 'My note' : lodashGet(personalDetailsList, [accountID, 'login'], ''), + icon: UserUtils.getAvatar(lodashGet(personalDetailsList, [accountID, 'avatar'], UserUtils.getDefaultAvatar(accountID)), accountID), + iconType: CONST.ICON_TYPE_AVATAR, + action: () => Navigation.navigate(ROUTES.getPrivateNotesViewRoute(report.reportID, accountID)), + brickRoadIndicator: privateNoteBrickRoadIndicator(accountID), + })) + .value(); + }, [report, personalDetailsList, session]); + + return ( + + Navigation.goBack()} + > + Navigation.dismissModal()} + onBackButtonPress={() => Navigation.goBack()} + /> + {report.isLoadingPrivateNotes && _.isEmpty(lodashGet(report, 'privateNotes', {})) ? ( + + ) : ( + _.map(privateNotes, (item, index) => getMenuItem(item, index)) + )} + + + ); +} + +PrivateNotesListPage.propTypes = propTypes; +PrivateNotesListPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`, + }, + session: { + key: ONYXKEYS.SESSION, + }, + personalDetailsList: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + }), + withNetwork(), +)(PrivateNotesListPage); diff --git a/src/pages/PrivateNotes/PrivateNotesViewPage.js b/src/pages/PrivateNotes/PrivateNotesViewPage.js new file mode 100644 index 000000000000..86814ed4dc92 --- /dev/null +++ b/src/pages/PrivateNotes/PrivateNotesViewPage.js @@ -0,0 +1,109 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {ScrollView} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; +import _ from 'underscore'; +import withLocalize from '../../components/withLocalize'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import HeaderWithBackButton from '../../components/HeaderWithBackButton'; +import Navigation from '../../libs/Navigation/Navigation'; +import styles from '../../styles/styles'; +import compose from '../../libs/compose'; +import ONYXKEYS from '../../ONYXKEYS'; +import ROUTES from '../../ROUTES'; +import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; +import reportPropTypes from '../reportPropTypes'; +import personalDetailsPropType from '../personalDetailsPropType'; +import useLocalize from '../../hooks/useLocalize'; +import OfflineWithFeedback from '../../components/OfflineWithFeedback'; +import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription'; +import CONST from '../../CONST'; + +const propTypes = { + /** All of the personal details for everyone */ + personalDetailsList: PropTypes.objectOf(personalDetailsPropType), + + /** The report currently being looked at */ + report: reportPropTypes, + route: PropTypes.shape({ + /** Params from the URL path */ + params: PropTypes.shape({ + /** reportID and accountID passed via route: /r/:reportID/notes */ + reportID: PropTypes.string, + accountID: PropTypes.string, + }), + }).isRequired, + + /** Session of currently logged in user */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), +}; + +const defaultProps = { + report: {}, + session: { + accountID: null, + }, + personalDetailsList: {}, +}; + +function PrivateNotesViewPage({route, personalDetailsList, session, report}) { + const {translate} = useLocalize(); + const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID); + const privateNote = lodashGet(report, ['privateNotes', route.params.accountID, 'note'], ''); + + return ( + + Navigation.goBack()} + > + Navigation.dismissModal()} + onBackButtonPress={() => Navigation.goBack()} + /> + + + isCurrentUserNote && Navigation.navigate(ROUTES.getPrivateNotesEditRoute(report.reportID, route.params.accountID))} + shouldShowRightIcon={isCurrentUserNote} + numberOfLinesTitle={0} + shouldRenderAsHTML + brickRoadIndicator={!_.isEmpty(lodashGet(report, ['privateNotes', route.params.accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + disabled={!isCurrentUserNote} + shouldGreyOutWhenDisabled={false} + /> + + + + + ); +} + +PrivateNotesViewPage.displayName = 'PrivateNotesViewPage'; +PrivateNotesViewPage.propTypes = propTypes; +PrivateNotesViewPage.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`, + }, + session: { + key: ONYXKEYS.SESSION, + }, + personalDetailsList: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + }), +)(PrivateNotesViewPage); diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index 22cac40cf29c..b306164a8ba0 100755 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -36,6 +36,7 @@ import * as Illustrations from '../components/Icon/Illustrations'; import variables from '../styles/variables'; import * as ValidationUtils from '../libs/ValidationUtils'; import Permissions from '../libs/Permissions'; +import ROUTES from '../ROUTES'; const matchType = PropTypes.shape({ params: PropTypes.shape({ @@ -140,6 +141,8 @@ function ProfilePage(props) { const navigateBackTo = lodashGet(props.route, 'params.backTo', ''); + const chatReportWithCurrentUser = !isCurrentUser && !Session.isAnonymousUser() ? ReportUtils.getChatByParticipants([accountID]) : 0; + return ( )} + {!_.isEmpty(chatReportWithCurrentUser) && ( + Navigation.navigate(ROUTES.getPrivateNotesListRoute(chatReportWithCurrentUser.reportID))} + wrapperStyle={styles.breakAll} + shouldShowRightIcon + brickRoadIndicator={Report.hasErrorInPrivateNotes(chatReportWithCurrentUser) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + /> + )} )} {!hasMinimumDetails && isLoading && } diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 7a3373a8428c..3a9e0f5c2eb8 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -112,6 +112,18 @@ function ReportDetailsPage(props) { }); } + // Prevent displaying private notes option for threads and task reports + if (!isThread && !ReportUtils.isTaskReport(props.report)) { + items.push({ + key: CONST.REPORT_DETAILS_MENU_ITEM.PRIVATE_NOTES, + translationKey: 'privateNotes.title', + icon: Expensicons.Pencil, + isAnonymousAction: false, + action: () => Navigation.navigate(ROUTES.getPrivateNotesListRoute(props.report.reportID)), + brickRoadIndicator: Report.hasErrorInPrivateNotes(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '', + }); + } + if (isUserCreatedPolicyRoom || canLeaveRoom || isThread) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.LEAVE_ROOM, @@ -123,7 +135,7 @@ function ReportDetailsPage(props) { } return items; - }, [props.report.reportID, participants, isArchivedRoom, shouldDisableSettings, isThread, isUserCreatedPolicyRoom, canLeaveRoom]); + }, [props.report, participants, isArchivedRoom, shouldDisableSettings, isThread, isUserCreatedPolicyRoom, canLeaveRoom]); const displayNamesWithTooltips = useMemo(() => { const hasMultipleParticipants = participants.length > 1; @@ -187,7 +199,7 @@ function ReportDetailsPage(props) { onPress={item.action} isAnonymousAction={item.isAnonymousAction} shouldShowRightIcon - brickRoadIndicator={brickRoadIndicator} + brickRoadIndicator={brickRoadIndicator || item.brickRoadIndicator} /> ); })}