diff --git a/src/components/Form.js b/src/components/Form.js index 7048fc4d192d..f5814c7b29cf 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -209,8 +209,8 @@ function Form(props) { * @returns {React.Component} */ const childrenWrapperWithProps = useCallback( - (childNodes) => - React.Children.map(childNodes, (child) => { + (childNodes) => { + const childrenElements = React.Children.map(childNodes, (child) => { // Just render the child if it is not a valid React element, e.g. text within a component if (!React.isValidElement(child)) { return child; @@ -330,7 +330,28 @@ function Form(props) { } }, }); - }), + }); + + // We need to verify that all references and values are still actual. + // We should not store it when e.g. some input has been unmounted + _.each(inputRefs.current, (inputRef, inputID) => { + if (inputRef) { + return; + } + + delete inputRefs.current[inputID]; + + setInputValues((prevState) => { + const copyPrevState = _.clone(prevState); + + delete copyPrevState[inputID]; + + return copyPrevState; + }); + }); + + return childrenElements; + }, [errors, inputRefs, inputValues, onValidate, props.draftValues, props.formID, props.formState, setTouchedInput], ); diff --git a/src/languages/en.js b/src/languages/en.js index 33fc3f3e74c7..a1df88acb55e 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -288,6 +288,8 @@ export default { beginningOfChatHistoryDomainRoomPartTwo: ' to chat with colleagues, share tips, and ask questions.', beginningOfChatHistoryAdminRoomPartOne: ({workspaceName}) => `Collaboration among ${workspaceName} admins starts here! 🎉\nUse `, beginningOfChatHistoryAdminRoomPartTwo: ' to chat about topics such as workspace configurations and more.', + beginningOfChatHistoryAdminOnlyPostingRoomPartOne: 'Use ', + beginningOfChatHistoryAdminOnlyPostingRoomPartTwo: ({workspaceName}) => ` to hear about important announcements related to ${workspaceName}`, beginningOfChatHistoryAnnounceRoomPartOne: ({workspaceName}) => `Collaboration between all ${workspaceName} members starts here! 🎉\nUse `, beginningOfChatHistoryAnnounceRoomPartTwo: ({workspaceName}) => ` to chat about anything ${workspaceName} related.`, beginningOfChatHistoryUserRoomPartOne: 'Collaboration starts here! 🎉\nUse this space to chat about anything ', diff --git a/src/languages/es.js b/src/languages/es.js index b481f89b4940..65de4495768f 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -287,6 +287,8 @@ export default { beginningOfChatHistoryDomainRoomPartTwo: ' para chatear con compañeros, compartir consejos o hacer una pregunta.', beginningOfChatHistoryAdminRoomPartOne: ({workspaceName}) => `Este es el lugar para que los administradores de ${workspaceName} colaboren! 🎉\nUsa `, beginningOfChatHistoryAdminRoomPartTwo: ' para chatear sobre temas como la configuración del espacio de trabajo y mas.', + beginningOfChatHistoryAdminOnlyPostingRoomPartOne: 'Utiliza ', + beginningOfChatHistoryAdminOnlyPostingRoomPartTwo: ({workspaceName}) => ` para enterarte de anuncios importantes relacionados con ${workspaceName}`, beginningOfChatHistoryAnnounceRoomPartOne: ({workspaceName}) => `Este es el lugar para que todos los miembros de ${workspaceName} colaboren! 🎉\nUsa `, beginningOfChatHistoryAnnounceRoomPartTwo: ({workspaceName}) => ` para chatear sobre cualquier cosa relacionada con ${workspaceName}.`, beginningOfChatHistoryUserRoomPartOne: 'Este es el lugar para colaborar! 🎉\nUsa este espacio para chatear sobre cualquier cosa relacionada con ', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 81b34d8c73a0..359c729b1aee 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -274,6 +274,16 @@ function isAdminRoom(report) { return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS; } +/** + * Whether the provided report is an Admin-only posting room + * @param {Object} report + * @param {String} report.writeCapability + * @returns {Boolean} + */ +function isAdminsOnlyPostingRoom(report) { + return lodashGet(report, 'writeCapability', CONST.REPORT.WRITE_CAPABILITIES.ALL) === CONST.REPORT.WRITE_CAPABILITIES.ADMINS; +} + /** * Whether the provided report is a Announce room * @param {Object} report @@ -567,6 +577,18 @@ function isPolicyExpenseChatAdmin(report, policies) { return policyRole === CONST.POLICY.ROLE.ADMIN; } +/** + * Checks if the current user is the admin of the policy. + * @param {String} policyID + * @param {Object} policies must have OnyxKey prefix (i.e 'policy_') for keys + * @returns {Boolean} + */ +function isPolicyAdmin(policyID, policies) { + const policyRole = lodashGet(policies, [`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, 'role']); + + return policyRole === CONST.POLICY.ROLE.ADMIN; +} + /** * Returns true if report is a DM/Group DM chat. * @@ -663,6 +685,9 @@ function getRoomWelcomeMessage(report) { } else if (isAdminRoom(report)) { welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAdminRoomPartOne', {workspaceName}); welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAdminRoomPartTwo'); + } else if (isAdminsOnlyPostingRoom(report)) { + welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAdminOnlyPostingRoomPartOne'); + welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAdminOnlyPostingRoomPartTwo', {workspaceName}); } else if (isAnnounceRoom(report)) { welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartOne', {workspaceName}); welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartTwo', {workspaceName}); @@ -1730,6 +1755,7 @@ function buildOptimisticTaskReportAction(taskReportID, actionName, message = '') * @param {Boolean} isOwnPolicyExpenseChat * @param {String} oldPolicyName * @param {String} visibility + * @param {String} writeCapability * @param {String} notificationPreference * @param {String} parentReportActionID * @param {String} parentReportID @@ -1744,6 +1770,7 @@ function buildOptimisticChatReport( isOwnPolicyExpenseChat = false, oldPolicyName = '', visibility = undefined, + writeCapability = CONST.REPORT.WRITE_CAPABILITIES.ALL, notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, parentReportActionID = '', parentReportID = '', @@ -1774,6 +1801,7 @@ function buildOptimisticChatReport( statusNum: 0, visibility, welcomeMessage: '', + writeCapability, }; } @@ -2653,6 +2681,7 @@ export { getPolicyType, isArchivedRoom, isPolicyExpenseChatAdmin, + isPolicyAdmin, isPublicRoom, isPublicAnnounceRoom, isConciergeChatReport, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 1b535f72fca9..fe01bd95fffc 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1264,8 +1264,9 @@ function navigateToConciergeChat() { * @param {String} reportName * @param {String} visibility * @param {Array} policyMembersAccountIDs + * @param {String} writeCapability */ -function addPolicyReport(policyID, reportName, visibility, policyMembersAccountIDs) { +function addPolicyReport(policyID, reportName, visibility, policyMembersAccountIDs, writeCapability) { // The participants include the current user (admin), and for restricted rooms, the policy members. Participants must not be empty. const members = visibility === CONST.REPORT.VISIBILITY.RESTRICTED ? policyMembersAccountIDs : []; const participants = _.unique([currentUserAccountID, ...members]); @@ -1278,6 +1279,7 @@ function addPolicyReport(policyID, reportName, visibility, policyMembersAccountI false, '', visibility, + writeCapability, // The room might contain all policy members so notifying always should be opt-in only. CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, @@ -1344,6 +1346,7 @@ function addPolicyReport(policyID, reportName, visibility, policyMembersAccountI visibility, reportID: policyReport.reportID, createdReportActionID: createdReportAction.reportActionID, + writeCapability, }, {optimisticData, successData, failureData}, ); diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 90a1cdb464fe..e8d861fc2ef6 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useState} from 'react'; import Animated, {useSharedValue, useAnimatedStyle, withTiming} from 'react-native-reanimated'; import _ from 'underscore'; +import lodashGet from 'lodash/get'; import InvertedFlatList from '../../../components/InvertedFlatList'; import compose from '../../../libs/compose'; import styles from '../../../styles/styles'; @@ -162,6 +163,12 @@ function ReportActionsList(props) { // To notify there something changes we can use extraData prop to flatlist const extraData = [props.isSmallScreenWidth ? props.newMarkerReportActionID : undefined, ReportUtils.isArchivedRoom(props.report)]; const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(props.personalDetailsList, props.report, props.currentUserPersonalDetails.accountID); + + const errors = lodashGet(props.report, 'errorFields.addWorkspaceRoom') || lodashGet(props.report, 'errorFields.createChat'); + const isArchivedRoom = ReportUtils.isArchivedRoom(props.report); + const hideComposer = ReportUtils.shouldHideComposer(props.report, errors); + const shouldOmitBottomSpace = hideComposer || isArchivedRoom; + return ( translate(`newRoomPage.${visibility}Description`), [translate, visibility]); + const isPolicyAdmin = useMemo(() => { + if (!policyID) { + return false; + } + + return ReportUtils.isPolicyAdmin(policyID, props.policies); + }, [policyID, props.policies]); /** * @param {Object} values - form input values passed by the Form component */ const submit = (values) => { const policyMembers = _.map(_.keys(props.allPolicyMembers[`${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${values.policyID}`]), (accountID) => Number(accountID)); - Report.addPolicyReport(values.policyID, values.roomName, values.visibility, policyMembers); + Report.addPolicyReport(values.policyID, values.roomName, values.visibility, policyMembers, values.writeCapability); }; /** @@ -109,6 +118,15 @@ function WorkspaceNewRoomPage(props) { const workspaceOptions = useMemo(() => _.map(PolicyUtils.getActivePolicies(props.policies), (policy) => ({label: policy.name, key: policy.id, value: policy.id})), [props.policies]); + const writeCapabilityOptions = useMemo( + () => + _.map(CONST.REPORT.WRITE_CAPABILITIES, (value) => ({ + value, + label: translate(`writeCapabilityPage.writeCapability.${value}`), + })), + [translate], + ); + const visibilityOptions = useMemo( () => _.map( @@ -156,14 +174,25 @@ function WorkspaceNewRoomPage(props) { shouldDelayFocus={shouldDelayFocus} /> - + + {isPolicyAdmin && ( + + + + )}