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

Fix leave option does not appear in group chat thread #40529

Merged
merged 23 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
101 changes: 99 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5522,6 +5522,40 @@ function temporary_getMoneyRequestOptions(
return getMoneyRequestOptions(report, policy, reportParticipants, canUseTrackExpense, true) as Array<Exclude<IOUType, typeof CONST.IOU.TYPE.REQUEST | typeof CONST.IOU.TYPE.SEND>>;
}

/**
* Invoice sender, invoice receiver and auto-invited admins cannot leave
*/
function canLeaveInvoiceRoom(report: OnyxEntry<Report>): boolean {
if (!isInvoiceRoom(report)) {
return false;
}

const invoiceReport = getReport(report?.iouReportID ?? '');

if (invoiceReport?.ownerAccountID === currentUserAccountID) {
return false;
}

if (invoiceReport?.managerID === currentUserAccountID) {
return false;
}

const isSenderPolicyAdmin = getPolicy(report?.policyID)?.role === CONST.POLICY.ROLE.ADMIN;

if (isSenderPolicyAdmin) {
return false;
}

const isReceiverPolicyAdmin =
report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS ? getPolicy(report?.invoiceReceiver?.policyID)?.role === CONST.POLICY.ROLE.ADMIN : false;

if (isReceiverPolicyAdmin) {
return false;
}

return true;
}

/**
* 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)
Expand Down Expand Up @@ -5984,6 +6018,13 @@ function isDeprecatedGroupDM(report: OnyxEntry<Report>): boolean {
);
}

/**
* A "root" group chat is the top level group chat and does not refer to any threads off of a Group Chat
*/
function isRootGroupChat(report: OnyxEntry<Report>): boolean {
marcaaron marked this conversation as resolved.
Show resolved Hide resolved
return !isChatThread(report) && (isGroupChat(report) || isDeprecatedGroupDM(report));
}

/**
* Assume any report without a reportID is unusable.
*/
Expand Down Expand Up @@ -6400,10 +6441,63 @@ function hasActionsWithErrors(reportID: string): boolean {
return Object.values(reportActions).some((action) => !isEmptyObject(action.errors));
}

function canLeavePolicyExpenseChat(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
function isNonAdminOrOwnerOfPolicyExpenseChat(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
return isPolicyExpenseChat(report) && !(PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report));
}

/**
* Whether the user can join a report
*/
function canJoinChat(report: OnyxEntry<Report>, parentReportAction: OnyxEntry<ReportAction>, policy: OnyxEntry<Policy>): boolean {
// We disabled thread functions for whisper action
// So we should not show join option for existing thread on whisper message that has already been left, or manually leave it
if (ReportActionsUtils.isWhisperAction(parentReportAction)) {
marcaaron marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

// If the notification preference of the chat is not hidden that means we have already joined the chat
if (report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) {
marcaaron marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

// Anyone viewing these chat types is already a participant and therefore cannot join
if (isRootGroupChat(report) || isSelfDM(report) || isInvoiceRoom(report)) {
return false;
}

// The user who is a member of the workspace has already joined the public announce room.
if (isPublicAnnounceRoom(report) && !isEmptyObject(policy)) {
return false;
}

return isChatThread(report) || isUserCreatedPolicyRoom(report) || isNonAdminOrOwnerOfPolicyExpenseChat(report, policy);
}

/**
* Whether the user can leave a report
*/
function canLeaveChat(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave chat doesn't make sense for anonymous users since they haven't actually joined.
Issue: #43404

if (report?.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) {
return false;
}

// Anyone viewing these chat types is already a participant and therefore cannot leave
if (isSelfDM(report) || isRootGroupChat(report)) {
return false;
}

// The user who is a member of the workspace cannot leave the public announce room.
if (isPublicAnnounceRoom(report) && !isEmptyObject(policy)) {
return false;
}

if (canLeaveInvoiceRoom(report)) {
return true;
}

return (isChatThread(report) && !!report?.notificationPreference?.length) || isUserCreatedPolicyRoom(report) || isNonAdminOrOwnerOfPolicyExpenseChat(report, policy);
}

function getReportActionActorAccountID(reportAction: OnyxEntry<ReportAction>, iouReport: OnyxEntry<Report> | undefined): number | undefined {
switch (reportAction?.actionName) {
case CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW:
Expand Down Expand Up @@ -6559,8 +6653,10 @@ export {
canEditRoomVisibility,
canEditWriteCapability,
canFlagReportAction,
canLeavePolicyExpenseChat,
isNonAdminOrOwnerOfPolicyExpenseChat,
canLeaveRoom,
canJoinChat,
canLeaveChat,
canReportBeMentionedWithinPolicy,
canRequestMoney,
canSeeDefaultRoom,
Expand Down Expand Up @@ -6688,6 +6784,7 @@ export {
isDM,
isDefaultRoom,
isDeprecatedGroupDM,
isRootGroupChat,
isExpenseReport,
isExpenseRequest,
isExpensifyOnlyParticipantInReport,
Expand Down
11 changes: 2 additions & 9 deletions src/pages/home/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import * as HeaderUtils from '@libs/HeaderUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as Link from '@userActions/Link';
import * as Report from '@userActions/Report';
Expand Down Expand Up @@ -106,13 +105,9 @@ function HeaderView({
const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(reportHeaderData);
const isConcierge = ReportUtils.hasSingleParticipant(report) && participants.includes(CONST.ACCOUNT_ID.CONCIERGE);
const isCanceledTaskReport = ReportUtils.isCanceledTaskReport(report, parentReportAction);
const isWhisperAction = ReportActionsUtils.isWhisperAction(parentReportAction);
const isUserCreatedPolicyRoom = ReportUtils.isUserCreatedPolicyRoom(report);
const isPolicyEmployee = useMemo(() => !isEmptyObject(policy), [policy]);
const canLeaveRoom = ReportUtils.canLeaveRoom(report, isPolicyEmployee);
const reportDescription = ReportUtils.getReportDescriptionText(report);
const policyName = ReportUtils.getPolicyName(report, true);
const canLeavePolicyExpenseChat = ReportUtils.canLeavePolicyExpenseChat(report, policy);
const policyDescription = ReportUtils.getPolicyDescriptionText(policy);
const isPersonalExpenseChat = isPolicyExpenseChat && ReportUtils.isCurrentUserSubmitter(report.reportID);
const shouldShowSubtitle = () => {
Expand Down Expand Up @@ -157,16 +152,14 @@ function HeaderView({
Report.updateNotificationPreference(reportID, report.notificationPreference, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, false, report.parentReportID, report.parentReportActionID),
);

const canJoinOrLeave = !isSelfDM && !isGroupChat && (isChatThread || isUserCreatedPolicyRoom || canLeaveRoom || canLeavePolicyExpenseChat);
const canJoin = canJoinOrLeave && !isWhisperAction && report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
const canLeave = canJoinOrLeave && ((isChatThread && !!report.notificationPreference?.length) || isUserCreatedPolicyRoom || canLeaveRoom || canLeavePolicyExpenseChat);
const canJoin = ReportUtils.canJoinChat(report, parentReportAction, policy);
if (canJoin) {
threeDotMenuItems.push({
icon: Expensicons.ChatBubbles,
text: translate('common.join'),
onSelected: join,
});
} else if (canLeave) {
} else if (ReportUtils.canLeaveChat(report, policy)) {
const isWorkspaceMemberLeavingWorkspaceRoom = !isChatThread && (report.visibility === CONST.REPORT.VISIBILITY.RESTRICTED || isPolicyExpenseChat) && isPolicyEmployee;
threeDotMenuItems.push({
icon: Expensicons.ChatBubbles,
Expand Down
Loading