Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polish admins-only policy room feature #21950

Merged
merged 39 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b8198c8
add writeCapability to create new room
rezkiy37 Jun 27, 2023
823d28a
update admin room welcome message
rezkiy37 Jun 27, 2023
43a46cc
filter out admin-only rooms for members
rezkiy37 Jun 27, 2023
8135994
Revert "update admin room welcome message"
rezkiy37 Jun 27, 2023
a937311
update admin room welcome message
rezkiy37 Jun 27, 2023
42e21d7
fix reports visibility
rezkiy37 Jun 27, 2023
3cacb87
remove extra space for offline indicator
rezkiy37 Jun 27, 2023
e7e9cae
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jun 28, 2023
fc6d024
omit padding bottom of ReportActionItemCreated
rezkiy37 Jun 28, 2023
b298dea
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jun 30, 2023
e40d85c
Apply destructuring assignment of values of validate method
rezkiy37 Jun 30, 2023
e16e167
Add JSDoc
rezkiy37 Jun 30, 2023
35807e8
Add dummy translation
rezkiy37 Jun 30, 2023
e526c7e
Add real translations
rezkiy37 Jul 1, 2023
78e9c5b
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 2, 2023
5ad14aa
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 3, 2023
5e0e492
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 4, 2023
ae5b9dd
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 6, 2023
e8d2625
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 7, 2023
2865c7f
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 14, 2023
36f9d56
restrict some actions
rezkiy37 Jul 14, 2023
f4c89d9
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 17, 2023
3c91515
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 18, 2023
c6279a9
Revert "restrict some actions"
rezkiy37 Jul 18, 2023
9654e73
Revert "remove extra space for offline indicator"
rezkiy37 Jul 18, 2023
8b7fe70
Revert "fix reports visibility"
rezkiy37 Jul 18, 2023
fbbf0b7
Revert "filter out admin-only rooms for members"
rezkiy37 Jul 18, 2023
c1f8509
one-line of isAdminsOnlyPostingRoom
rezkiy37 Jul 18, 2023
3b23219
revert redundant changes
rezkiy37 Jul 18, 2023
9e8e423
show write capability picker for admins only
rezkiy37 Jul 18, 2023
3b3f3c9
move down write capability picker
rezkiy37 Jul 18, 2023
e69102f
Revert "omit padding bottom of ReportActionItemCreated"
rezkiy37 Jul 18, 2023
50a6315
remove bottom spacing of messages list when no composer
rezkiy37 Jul 18, 2023
d1a792c
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 19, 2023
8a224fc
omit unmounted inputs of form
rezkiy37 Jul 19, 2023
ccc00ba
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 19, 2023
76ba533
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 24, 2023
38659cb
add a comment
rezkiy37 Jul 24, 2023
b886d07
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fea…
rezkiy37 Jul 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,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 ',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,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 ',
Expand Down
6 changes: 5 additions & 1 deletion src/libs/OptionsListUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ function getOptions(
includeThreads = false,
includeTasks = false,
includeMoneyRequests = false,
isShareDestination = false,
},
) {
if (!isPersonalDetailsReady(personalDetails)) {
Expand All @@ -624,7 +625,9 @@ function getOptions(
const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number.e164 : searchInputValue;

// Filter out all the reports that shouldn't be displayed
const filteredReports = _.filter(reports, (report) => ReportUtils.shouldReportBeInOptionList(report, Navigation.getReportIDFromRoute(), false, iouReports, betas, policies));
const filteredReports = _.filter(reports, (report) =>
ReportUtils.shouldReportBeInOptionList(report, Navigation.getReportIDFromRoute(), false, iouReports, betas, policies, isShareDestination),
);

// Sorting the reports works like this:
// - Order everything by the last message timestamp (descending)
Expand Down Expand Up @@ -955,6 +958,7 @@ function getShareDestinationOptions(reports, personalDetails, betas = [], search
includePersonalDetails: true,
excludeLogins,
includeOwnedWorkspaceChats,
isShareDestination: true,
});
}

Expand Down
29 changes: 28 additions & 1 deletion src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,18 @@ 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) {
const writeCapability = lodashGet(report, 'writeCapability', CONST.REPORT.WRITE_CAPABILITIES.ALL);

return writeCapability === CONST.REPORT.WRITE_CAPABILITIES.ADMINS;
amyevans marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Whether the provided report is a Announce room
* @param {Object} report
Expand Down Expand Up @@ -576,6 +588,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});
Expand Down Expand Up @@ -1534,6 +1549,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
Expand All @@ -1549,6 +1565,7 @@ function buildOptimisticChatReport(
isOwnPolicyExpenseChat = false,
oldPolicyName = '',
visibility = undefined,
writeCapability = CONST.REPORT.WRITE_CAPABILITIES.ALL,
notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS,
parentReportActionID = '',
parentReportID = '',
Expand Down Expand Up @@ -1580,6 +1597,7 @@ function buildOptimisticChatReport(
statusNum: 0,
visibility,
welcomeMessage: '',
writeCapability,
};
}

Expand Down Expand Up @@ -1950,9 +1968,10 @@ function canAccessReport(report, policies, betas) {
* @param {Object} iouReports
* @param {String[]} betas
* @param {Object} policies
* @param {Boolean} isShareDestination
* @returns {boolean}
*/
function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, iouReports, betas, policies) {
function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, iouReports, betas, policies, isShareDestination = false) {
const isInDefaultMode = !isInGSDMode;

// Exclude reports that have no data because there wouldn't be anything to show in the option item.
Expand Down Expand Up @@ -2004,6 +2023,14 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, iouRep
return false;
}

// Exclude reports that are admin-only posting rooms, when the user tries to share something to the room,
// because, the user isn't an admin for a linked workspace.
if (isShareDestination && report.writeCapability === CONST.REPORT.WRITE_CAPABILITIES.ADMINS) {
const linkedWorkspace = _.find(policies, (policy) => policy && policy.id === report.policyID);

return lodashGet(linkedWorkspace, 'role', '') === CONST.POLICY.ROLE.ADMIN;
}

// Hide thread reports that haven't been commented on
if (isThread(report) && !report.lastMessageText) {
return false;
Expand Down
5 changes: 4 additions & 1 deletion src/libs/actions/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -1198,8 +1198,9 @@ function navigateToConciergeChat() {
* @param {String} reportName
* @param {String} visibility
* @param {Array} policyMembers
* @param {String} writeCapability
*/
function addPolicyReport(policyID, reportName, visibility, policyMembers) {
function addPolicyReport(policyID, reportName, visibility, policyMembers, writeCapability) {
// The participants include the current user (admin) and the employees. Participants must not be empty.
const participants = _.unique([currentUserAccountID, ...policyMembers]);
const policyReport = ReportUtils.buildOptimisticChatReport(
Expand All @@ -1212,6 +1213,7 @@ function addPolicyReport(policyID, reportName, visibility, policyMembers) {
false,
'',
visibility,
writeCapability,

// The room might contain all policy members so notifying always should be opt-in only.
CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY,
Expand Down Expand Up @@ -1278,6 +1280,7 @@ function addPolicyReport(policyID, reportName, visibility, policyMembers) {
visibility,
reportID: policyReport.reportID,
createdReportActionID: createdReportAction.reportActionID,
writeCapability,
},
{optimisticData, successData, failureData},
);
Expand Down
7 changes: 6 additions & 1 deletion src/pages/home/report/ReportActionItemCreated.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ function ReportActionItemCreated(props) {

const icons = ReportUtils.getIcons(props.report, props.personalDetails);

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 = props.report.lastMessageText === '' && (isArchivedRoom || hideComposer);

return (
<OfflineWithFeedback
pendingAction={lodashGet(props.report, 'pendingFields.addWorkspaceRoom') || lodashGet(props.report, 'pendingFields.createChat')}
Expand All @@ -68,7 +73,7 @@ function ReportActionItemCreated(props) {
/>
<View
accessibilityLabel={props.translate('accessibilityHints.chatWelcomeMessage')}
style={[styles.p5, StyleUtils.getReportWelcomeTopMarginStyle(props.isSmallScreenWidth)]}
style={[styles.p5, shouldOmitBottomSpace && styles.pb0, StyleUtils.getReportWelcomeTopMarginStyle(props.isSmallScreenWidth)]}
amyevans marked this conversation as resolved.
Show resolved Hide resolved
>
<PressableWithoutFeedback
onPress={() => ReportUtils.navigateToDetailsPage(props.report)}
Expand Down
4 changes: 1 addition & 3 deletions src/pages/home/report/ReportFooter.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ function ReportFooter(props) {
{(isArchivedRoom || hideComposer) && (
<View style={[styles.chatFooter, props.isSmallScreenWidth ? styles.mb5 : null]}>
{isArchivedRoom && <ArchivedReportFooter report={props.report} />}
{!props.isSmallScreenWidth && (
<View style={styles.offlineIndicatorRow}>{hideComposer && <OfflineIndicator containerStyles={[styles.chatItemComposeSecondaryRow]} />}</View>
)}
{!props.isSmallScreenWidth && <OfflineIndicator containerStyles={[styles.chatItemComposeSecondaryRow]} />}
amyevans marked this conversation as resolved.
Show resolved Hide resolved
</View>
)}
{!hideComposer && (props.shouldShowComposeInput || !props.isSmallScreenWidth) && (
Expand Down
35 changes: 24 additions & 11 deletions src/pages/workspace/WorkspaceNewRoomPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ class WorkspaceNewRoomPage extends React.Component {
/**
* @param {Object} values - form input values passed by the Form component
*/
submit(values) {
const policyMembers = _.map(_.keys(this.props.allPolicyMembers[`${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${values.policyID}`]), (accountID) => Number(accountID));
Report.addPolicyReport(values.policyID, values.roomName, values.visibility, policyMembers);
submit({policyID, roomName, visibility, writeCapability}) {
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved
const policyMembers = _.map(_.keys(this.props.allPolicyMembers[`${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`]), (accountID) => Number(accountID));
Report.addPolicyReport(policyID, roomName, visibility, policyMembers, writeCapability);
}

/**
Expand All @@ -101,24 +101,24 @@ class WorkspaceNewRoomPage extends React.Component {
* @param {Object} values - form input values passed by the Form component
* @returns {Boolean}
*/
validate(values) {
validate({policyID, roomName}) {
const errors = {};

if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) {
if (!roomName || roomName === CONST.POLICY.ROOM_PREFIX) {
// We error if the user doesn't enter a room name or left blank
ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.pleaseEnterRoomName');
} else if (values.roomName !== CONST.POLICY.ROOM_PREFIX && !ValidationUtils.isValidRoomName(values.roomName)) {
} else if (roomName !== CONST.POLICY.ROOM_PREFIX && !ValidationUtils.isValidRoomName(roomName)) {
// We error if the room name has invalid characters
ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomNameInvalidError');
} else if (ValidationUtils.isReservedRoomName(values.roomName)) {
} else if (ValidationUtils.isReservedRoomName(roomName)) {
// Certain names are reserved for default rooms and should not be used for policy rooms.
ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]);
} else if (ValidationUtils.isExistingRoomName(values.roomName, this.props.reports, values.policyID)) {
ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: roomName}]);
} else if (ValidationUtils.isExistingRoomName(roomName, this.props.reports, policyID)) {
// Certain names are reserved for default rooms and should not be used for policy rooms.
ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError');
}

if (!values.policyID) {
if (!policyID) {
errors.policyID = 'newRoomPage.pleaseSelectWorkspace';
}

Expand All @@ -132,6 +132,11 @@ class WorkspaceNewRoomPage extends React.Component {
return null;
}

const writeCapabilityOptions = _.map(CONST.REPORT.WRITE_CAPABILITIES, (value) => ({
value,
label: this.props.translate(`writeCapabilityPage.writeCapability.${value}`),
}));

// Workspaces are policies with type === 'free'
const workspaceOptions = _.map(
_.filter(this.props.policies, (policy) => policy && policy.type === CONST.POLICY.TYPE.FREE),
Expand Down Expand Up @@ -169,7 +174,15 @@ class WorkspaceNewRoomPage extends React.Component {
shouldDelayFocus={shouldDelayFocus}
/>
</View>
<View style={styles.mb5}>
<View style={styles.mb2}>
<Picker
inputID="writeCapability"
label={this.props.translate('writeCapabilityPage.label')}
items={writeCapabilityOptions}
defaultValue={CONST.REPORT.WRITE_CAPABILITIES.ALL}
/>
</View>
<View style={styles.mb2}>
<Picker
inputID="policyID"
label={this.props.translate('workspace.common.workspace')}
Expand Down
4 changes: 0 additions & 4 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -803,10 +803,6 @@ const styles = {
paddingBottom: 5,
},

offlineIndicatorRow: {
height: 25,
},

// Actions
actionAvatar: {
borderRadius: 20,
Expand Down
4 changes: 4 additions & 0 deletions src/styles/utilities/spacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ export default {
paddingTop: 80,
},

pb0: {
paddingBottom: 0,
},

pb1: {
paddingBottom: 4,
},
Expand Down