diff --git a/src/CONST.js b/src/CONST.js index 30f9e24ae3e7..4de4c746e99e 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -352,8 +352,10 @@ const CONST = { ALWAYS: 'always', }, VISIBILITY: { - RESTRICTED: 'restricted', + PUBLIC: 'public', + PUBLIC_ANNOUNCE: 'public_announce', PRIVATE: 'private', + RESTRICTED: 'restricted', }, RESERVED_ROOM_NAMES: ['#admins', '#announce'], MAX_PREVIEW_AVATARS: 4, diff --git a/src/languages/en.js b/src/languages/en.js index 26d165afc8bf..ed172125461e 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1097,6 +1097,7 @@ export default { visibility: 'Visibility', restrictedDescription: 'People in your workspace can find this room', privateDescription: 'People invited to this room can find it', + publicDescription: 'Anyone can find it', createRoom: 'Create room', roomAlreadyExistsError: 'A room with this name already exists', roomNameReservedError: 'A room on this workspace already uses this name', @@ -1110,6 +1111,8 @@ export default { visibilityOptions: { restricted: 'Restricted', private: 'Private', + public: 'Public', + public_announce: 'Public Announce', }, }, statementPage: { diff --git a/src/languages/es.js b/src/languages/es.js index 6c87c1088e3c..aa4c1be56b7c 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1099,6 +1099,7 @@ export default { visibility: 'Visibilidad', restrictedDescription: 'Sólo las personas en tu espacio de trabajo pueden encontrar esta sala', privateDescription: 'Sólo las personas que están invitadas a esta sala pueden encontrarla', + publicDescription: 'Cualquiera puede encontrarlo', createRoom: 'Crea una sala de chat', roomAlreadyExistsError: 'Ya existe una sala con este nombre', roomNameReservedError: 'Una sala en este espacio de trabajo ya usa este nombre', @@ -1112,6 +1113,8 @@ export default { visibilityOptions: { restricted: 'Restringida', private: 'Privada', + public: 'Público', + public_announce: 'Anuncio Público', }, }, statementPage: { diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index a911ee26b005..f4cc48abcd71 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1534,12 +1534,44 @@ function getIOUOptions(report, reportParticipants, betas) { ]; } +/** + * Allows a user to leave a policy room according to the following conditions of the visibility or chatType rNVP: + * `public` - Anyone can leave (because anybody can join) + * `public_announce` - Only non-policy members can leave (it's auto-shared with policy members) + * `policy_admins` - Nobody can leave (it's auto-shared with all policy admins) + * `policy_announce` - Nobody can leave (it's auto-shared with all policy members) + * `policy` - Anyone can leave (though only policy members can join) + * `domain` - Nobody can leave (it's auto-shared with domain members) + * `dm` - Nobody can leave (it's auto-shared with users) + * `private` - Anybody can leave (though you can only be invited to join) + * + * @param {Object} report + * @param {String} report.visibility + * @param {String} report.chatType + * @param {Boolean} isPolicyMember + * @returns {Boolean} + */ +function canLeaveRoom(report, isPolicyMember) { + if (_.isEmpty(report.visibility)) { + if (report.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS + || report.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE + || report.chatType === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL + || _.isEmpty(report.chatType)) { // DM chats don't have a chatType + return false; + } + } else if (report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE && isPolicyMember) { + return false; + } + return true; +} + export { getReportParticipantsTitle, isReportMessageAttachment, findLastAccessedReport, canEditReportAction, canDeleteReportAction, + canLeaveRoom, sortReportsByLastRead, isDefaultRoom, isAdminRoom, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index c269accf6ae1..86a587ed448c 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -14,6 +14,7 @@ import * as OptionsListUtils from '../OptionsListUtils'; import DateUtils from '../DateUtils'; import * as ReportUtils from '../ReportUtils'; import Log from '../Log'; +import * as Report from './Report'; const allPolicies = {}; Onyx.connect({ @@ -1000,6 +1001,38 @@ function openWorkspaceInvitePage(policyID, clientMemberEmails) { }); } +/** + * + * @param {String} reportID + */ +function leaveRoom(reportID) { + API.write('LeaveRoom', { + reportID, + }, { + optimisticData: [ + { + onyxMethod: CONST.ONYX.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS.CLOSED, + }, + }, + ], + failureData: [ + { + onyxMethod: CONST.ONYX.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + stateNum: CONST.REPORT.STATE_NUM.OPEN, + statusNum: CONST.REPORT.STATUS.OPEN, + }, + }, + ], + }); + Report.navigateToConciergeChat(); +} + export { removeMembers, addMembersToWorkspace, @@ -1027,4 +1060,5 @@ export { openWorkspaceMembersPage, openWorkspaceInvitePage, removeWorkspace, + leaveRoom, }; diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 02bd202c1d2c..5089b87c2742 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -15,6 +15,7 @@ import styles from '../styles/styles'; import DisplayNames from '../components/DisplayNames'; import * as OptionsListUtils from '../libs/OptionsListUtils'; import * as ReportUtils from '../libs/ReportUtils'; +import * as Policy from '../libs/actions/Policy'; import participantPropTypes from '../components/participantPropTypes'; import * as Expensicons from '../components/Icon/Expensicons'; import ROUTES from '../ROUTES'; @@ -86,14 +87,19 @@ class ReportDetailsPage extends Component { translationKey: 'common.invite', icon: Expensicons.Plus, action: () => { /* Placeholder for when inviting other users is built in */ }, - }, - { + }); + } + + const policy = this.props.policies[`${ONYXKEYS.COLLECTION.POLICY}${this.props.report.policyID}`]; + if (ReportUtils.isUserCreatedPolicyRoom(this.props.report) || ReportUtils.canLeaveRoom(this.props.report, !_.isEmpty(policy))) { + menuItems.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.LEAVE_ROOM, translationKey: 'common.leaveRoom', icon: Expensicons.Exit, - action: () => { /* Placeholder for when leaving rooms is built in */ }, + action: () => Policy.leaveRoom(this.props.report.reportID), }); } + return menuItems; } diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 0cc96e7ce33a..4db4670ac63e 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -117,7 +117,7 @@ class WorkspaceNewRoomPage extends React.Component { policy => ({label: policy.name, key: policy.id, value: policy.id}), ); - const visibilityOptions = _.map(_.values(CONST.REPORT.VISIBILITY), visibilityOption => ({ + const visibilityOptions = _.map(_.filter(_.values(CONST.REPORT.VISIBILITY), visibilityOption => visibilityOption !== CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE), visibilityOption => ({ label: this.props.translate(`newRoomPage.visibilityOptions.${visibilityOption}`), value: visibilityOption, description: this.props.translate(`newRoomPage.${visibilityOption}Description`),