From 0ceb6a43ebc87b0a2ea184859d837c36a3971a22 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 14 Jun 2022 15:38:07 -0400 Subject: [PATCH 1/4] Add exception for default rooms beta for users who are members of a free policy --- .../AppNavigator/MainDrawerNavigator.js | 32 ++++++++++++++++--- src/libs/OptionsListUtils.js | 10 +++++- src/libs/PolicyUtils.js | 30 +++++++++++++++++ src/libs/ReportUtils.js | 9 +++--- src/libs/actions/Policy.js | 13 -------- src/libs/actions/Welcome.js | 4 +-- src/pages/home/ReportScreen.js | 19 ++++++++++- .../SidebarScreen/BaseSidebarScreen.js | 3 +- 8 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 src/libs/PolicyUtils.js diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index 5201453768c9..4cf608d73572 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -13,6 +13,8 @@ import ReportScreen from '../../../pages/home/ReportScreen'; import SidebarScreen from '../../../pages/home/sidebar/SidebarScreen'; import BaseDrawerNavigator from './BaseDrawerNavigator'; import * as ReportUtils from '../../ReportUtils'; +import * as PolicyUtils from '../../PolicyUtils'; +import CONST from '../../../CONST'; const propTypes = { /** Available reports that would be displayed in this navigator */ @@ -22,6 +24,12 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), + + /** The policies which the user has access to */ + policies: PropTypes.shape({ + /** The policy name */ + name: PropTypes.string, + }).isRequired, }; const defaultProps = { @@ -33,11 +41,11 @@ const defaultProps = { * Get the most recently accessed report for the user * * @param {Object} reports - * @param {Boolean} [ignoreDefaultRooms] + * @param {String[]} [reportTypesToIgnore] * @returns {Object} */ -const getInitialReportScreenParams = (reports, ignoreDefaultRooms) => { - const last = ReportUtils.findLastAccessedReport(reports, ignoreDefaultRooms); +const getInitialReportScreenParams = (reports, reportTypesToIgnore) => { + const last = ReportUtils.findLastAccessedReport(reports, reportTypesToIgnore); // Fallback to empty if for some reason reportID cannot be derived - prevents the app from crashing const reportID = lodashGet(last, 'reportID', ''); @@ -45,7 +53,20 @@ const getInitialReportScreenParams = (reports, ignoreDefaultRooms) => { }; const MainDrawerNavigator = (props) => { - const initialParams = getInitialReportScreenParams(props.reports, !Permissions.canUseDefaultRooms(props.betas)); + // If one is a member of a free policy, then they are allowed to see the Policy default rooms. + // For everyone else, one must be on the beta to see a default room. + let reportTypesToIgnore = []; + const isMemberOfFreePolicy = PolicyUtils.isMemberOfFreePolicy(props.policies); + if (isMemberOfFreePolicy && !Permissions.canUseDefaultRooms(props.betas)) { + reportTypesToIgnore = [CONST.REPORT.CHAT_TYPE.DOMAIN_ALL]; + } else if (!Permissions.canUseDefaultRooms(props.betas)) { + reportTypesToIgnore = [ + CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, + CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, + CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, + ]; + } + const initialParams = getInitialReportScreenParams(props.reports, reportTypesToIgnore); // Wait until reports are fetched and there is a reportID in initialParams if (!initialParams.reportID) { @@ -81,5 +102,8 @@ export default withOnyx({ betas: { key: ONYXKEYS.BETAS, }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, })(MainDrawerNavigator); export {getInitialReportScreenParams}; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 2151679dcd83..a4cb2e13198a 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -10,6 +10,7 @@ import * as ReportUtils from './ReportUtils'; import * as Localize from './Localize'; import Permissions from './Permissions'; import * as CollectionUtils from './CollectionUtils'; +import * as PolicyUtils from './PolicyUtils'; /** * OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can @@ -439,7 +440,14 @@ function getOptions(reports, personalDetails, activeReportID, { return; } - if (ReportUtils.isDefaultRoom(report) && !Permissions.canUseDefaultRooms(betas)) { + // If one is a member of a free policy, then they are allowed to see the Policy default rooms. + // For everyone else, one must be on the beta to see a default room. + const isMemberOfFreePolicy = PolicyUtils.isMemberOfFreePolicy(policies); + if (isMemberOfFreePolicy && !Permissions.canUseDefaultRooms(this.props.betas)) { + if (ReportUtils.isDomainRoom(report)) { + return; + } + } else if (ReportUtils.isDefaultRoom(report) && !Permissions.canUseDefaultRooms(betas)) { return; } diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js new file mode 100644 index 000000000000..d225fd1982b7 --- /dev/null +++ b/src/libs/PolicyUtils.js @@ -0,0 +1,30 @@ +import _ from 'underscore'; +import CONST from '../CONST'; + +/** + * Is the user an admin of a free policy (aka workspace)? + * + * @param {Array} policies + * @returns {Boolean} + */ +function isAdminOfFreePolicy(policies) { + return _.some(policies, policy => policy + && policy.type === CONST.POLICY.TYPE.FREE + && policy.role === CONST.POLICY.ROLE.ADMIN); +} + +/** + * Is the user a member of a free policy (aka workspace)? + * + * @param {Array} policies + * @returns {Boolean} + */ +function isMemberOfFreePolicy(policies) { + return _.some(policies, policy => policy + && policy.type === CONST.POLICY.TYPE.FREE); +} + +export { + isAdminOfFreePolicy, + isMemberOfFreePolicy, +}; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3add040e848a..95f391e41238 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -172,14 +172,14 @@ function isChatRoom(report) { * Given a collection of reports returns the most recently accessed one * * @param {Record|Array<{lastVisitedTimestamp, reportID}>} reports - * @param {Boolean} [ignoreDefaultRooms] + * @param {String[]} [reportTypesToIgnore] * @returns {Object} */ -function findLastAccessedReport(reports, ignoreDefaultRooms) { +function findLastAccessedReport(reports, reportTypesToIgnore) { let sortedReports = sortReportsByLastVisited(reports); - if (ignoreDefaultRooms) { - sortedReports = _.filter(sortedReports, report => !isDefaultRoom(report)); + if (reportTypesToIgnore) { + sortedReports = _.filter(sortedReports, report => !_.contains(reportTypesToIgnore, lodashGet(report, ['chatType'], ''))); } return _.last(sortedReports); @@ -549,6 +549,7 @@ export { isDefaultRoom, isAdminRoom, isAnnounceRoom, + isDomainRoom, isUserCreatedPolicyRoom, isChatRoom, getChatRoomSubtitle, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index aa037a5cf692..ab522704268a 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -267,18 +267,6 @@ function loadFullPolicy(policyID) { }); } -/** - * Is the user an admin of a free policy (aka workspace)? - * - * @param {Array} policies - * @returns {Boolean} - */ -function isAdminOfFreePolicy(policies) { - return _.some(policies, policy => policy - && policy.type === CONST.POLICY.TYPE.FREE - && policy.role === CONST.POLICY.ROLE.ADMIN); -} - /** * Remove the passed members from the policy employeeList * @@ -550,7 +538,6 @@ export { loadFullPolicy, removeMembers, invite, - isAdminOfFreePolicy, create, uploadAvatar, update, diff --git a/src/libs/actions/Welcome.js b/src/libs/actions/Welcome.js index 41c559093941..0d2eeadff248 100644 --- a/src/libs/actions/Welcome.js +++ b/src/libs/actions/Welcome.js @@ -4,11 +4,11 @@ import lodashGet from 'lodash/get'; import Navigation from '../Navigation/Navigation'; import * as ReportUtils from '../ReportUtils'; import ROUTES from '../../ROUTES'; -import * as Policy from './Policy'; import ONYXKEYS from '../../ONYXKEYS'; import NameValuePair from './NameValuePair'; import CONST from '../../CONST'; import SCREENS from '../../SCREENS'; +import * as PolicyUtils from '../PolicyUtils'; let resolveIsReadyPromise; let isReadyPromise = new Promise((resolve) => { @@ -130,7 +130,7 @@ function show({routes, showCreateMenu}) { // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the create menu. - if (!Policy.isAdminOfFreePolicy(allPolicies) && !isDisplayingWorkspaceRoute) { + if (!PolicyUtils.isAdminOfFreePolicy(allPolicies) && !isDisplayingWorkspaceRoute) { showCreateMenu(); } }); diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index a0cb67ffbbeb..c660c22a8cd6 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -21,6 +21,7 @@ import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndica import reportActionPropTypes from './report/reportActionPropTypes'; import ArchivedReportFooter from '../../components/ArchivedReportFooter'; import toggleReportActionComposeView from '../../libs/toggleReportActionComposeView'; +import * as PolicyUtils from '../../libs/PolicyUtils'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -60,6 +61,12 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), + + /** The policies which the user has access to */ + policies: PropTypes.shape({ + /** The policy name */ + name: PropTypes.string, + }).isRequired, }; const defaultProps = { @@ -163,7 +170,14 @@ class ReportScreen extends React.Component { return null; } - if (!Permissions.canUseDefaultRooms(this.props.betas) && ReportUtils.isDefaultRoom(this.props.report)) { + // If one is a member of a free policy, then they are allowed to see the Policy default rooms. + // For everyone else, one must be on the beta to see a default room. + const isMemberOfFreePolicy = PolicyUtils.isMemberOfFreePolicy(this.props.policies); + if (isMemberOfFreePolicy && !Permissions.canUseDefaultRooms(this.props.betas)) { + if (ReportUtils.isDomainRoom(this.props.report)) { + return null; + } + } else if (ReportUtils.isDefaultRoom(this.props.report) && !Permissions.canUseDefaultRooms(this.props.betas)) { return null; } @@ -242,4 +256,7 @@ export default withOnyx({ betas: { key: ONYXKEYS.BETAS, }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, })(ReportScreen); diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js index a939c5bf4e19..f1b77faf5736 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js @@ -18,6 +18,7 @@ import * as Policy from '../../../../libs/actions/Policy'; import Performance from '../../../../libs/Performance'; import * as Welcome from '../../../../libs/actions/Welcome'; import {sidebarPropTypes, sidebarDefaultProps} from './sidebarPropTypes'; +import * as PolicyUtils from '../../../../libs/PolicyUtils'; const propTypes = { @@ -163,7 +164,7 @@ class BaseSidebarScreen extends Component { onSelected: () => Navigation.navigate(ROUTES.IOU_BILL), }, ] : []), - ...(!this.props.isCreatingWorkspace && !Policy.isAdminOfFreePolicy(this.props.allPolicies) ? [ + ...(!this.props.isCreatingWorkspace && !PolicyUtils.isAdminOfFreePolicy(this.props.allPolicies) ? [ { icon: Expensicons.NewWorkspace, iconWidth: 46, From 595196bb0b28f74705b4ac7f3a8f70fadb7f5362 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 14 Jun 2022 15:58:09 -0400 Subject: [PATCH 2/4] Fix small copy paste error --- src/libs/OptionsListUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index a4cb2e13198a..1c14871ba006 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -443,7 +443,7 @@ function getOptions(reports, personalDetails, activeReportID, { // If one is a member of a free policy, then they are allowed to see the Policy default rooms. // For everyone else, one must be on the beta to see a default room. const isMemberOfFreePolicy = PolicyUtils.isMemberOfFreePolicy(policies); - if (isMemberOfFreePolicy && !Permissions.canUseDefaultRooms(this.props.betas)) { + if (isMemberOfFreePolicy && !Permissions.canUseDefaultRooms(betas)) { if (ReportUtils.isDomainRoom(report)) { return; } From 1b172b5d31ee070ec81cfad42da1a8705adbd3dc Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Wed, 15 Jun 2022 12:01:12 -0400 Subject: [PATCH 3/4] Add type prop --- src/libs/Navigation/AppNavigator/MainDrawerNavigator.js | 3 +++ src/pages/home/ReportScreen.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index 4cf608d73572..02b71388aaf1 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -29,6 +29,9 @@ const propTypes = { policies: PropTypes.shape({ /** The policy name */ name: PropTypes.string, + + /** The type of the policy */ + type: PropTypes.string, }).isRequired, }; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 4f0b61e37da2..d7183ed1c65d 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -71,6 +71,9 @@ const propTypes = { policies: PropTypes.shape({ /** The policy name */ name: PropTypes.string, + + /** The type of the policy */ + type: PropTypes.string, }).isRequired, }; From af92cd9ac1e7955294d7465df9c9a441757c05b1 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Wed, 15 Jun 2022 17:01:26 -0400 Subject: [PATCH 4/4] use objectOf --- src/libs/Navigation/AppNavigator/MainDrawerNavigator.js | 4 ++-- src/pages/home/ReportScreen.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index 02b71388aaf1..3f966d71e6bb 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -26,13 +26,13 @@ const propTypes = { betas: PropTypes.arrayOf(PropTypes.string), /** The policies which the user has access to */ - policies: PropTypes.shape({ + policies: PropTypes.objectOf(PropTypes.shape({ /** The policy name */ name: PropTypes.string, /** The type of the policy */ type: PropTypes.string, - }).isRequired, + })).isRequired, }; const defaultProps = { diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index d7183ed1c65d..4b4faa4d7013 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -68,13 +68,13 @@ const propTypes = { betas: PropTypes.arrayOf(PropTypes.string), /** The policies which the user has access to */ - policies: PropTypes.shape({ + policies: PropTypes.objectOf(PropTypes.shape({ /** The policy name */ name: PropTypes.string, /** The type of the policy */ type: PropTypes.string, - }).isRequired, + })).isRequired, }; const defaultProps = {