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

[CP Staging] Revert "Move Leave button into a row of the Report Details page" #41818

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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,7 @@ const CONST = {
INFO: 'info',
},
REPORT_DETAILS_MENU_ITEM: {
SHARE_CODE: 'shareCode',
MEMBERS: 'member',
INVITE: 'invite',
SETTINGS: 'settings',
Expand Down
40 changes: 29 additions & 11 deletions src/components/ChatDetailsQuickActionsBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import React, {useState} from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as Report from '@userActions/Report';
import ROUTES from '@src/ROUTES';
import type {Report as OnyxReportType} from '@src/types/onyx';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import * as Expensicons from './Icon/Expensicons';

type ChatDetailsQuickActionsBarProps = {
Expand All @@ -15,26 +14,45 @@ type ChatDetailsQuickActionsBarProps = {

function ChatDetailsQuickActionsBar({report}: ChatDetailsQuickActionsBarProps) {
const styles = useThemeStyles();
const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false);
const {translate} = useLocalize();
const isPinned = !!report.isPinned;
return (
<View style={[styles.flexRow, styles.ph5, styles.mb5]}>
<View style={[styles.flex1, styles.pr3]}>
<ConfirmModal
danger
title={translate('groupChat.lastMemberTitle')}
isVisible={isLastMemberLeavingGroupModalVisible}
onConfirm={() => {
setIsLastMemberLeavingGroupModalVisible(false);
Report.leaveGroupChat(report.reportID);
}}
onCancel={() => setIsLastMemberLeavingGroupModalVisible(false)}
prompt={translate('groupChat.lastMemberWarning')}
confirmText={translate('common.leave')}
cancelText={translate('common.cancel')}
/>
<Button
onPress={() => Report.togglePinnedState(report.reportID, isPinned)}
icon={Expensicons.Pin}
onPress={() => {
if (Object.keys(report?.participants ?? {}).length === 1) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}

Report.leaveGroupChat(report.reportID);
}}
icon={Expensicons.Exit}
style={styles.flex1}
text={isPinned ? translate('common.unPin') : translate('common.pin')}
text={translate('common.leave')}
/>
</View>
<View style={[styles.flex1]}>
<Button
onPress={() => {
Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(report?.reportID ?? ''));
}}
icon={Expensicons.QrCode}
onPress={() => Report.togglePinnedState(report.reportID, isPinned)}
icon={Expensicons.Pin}
style={styles.flex1}
text={translate('common.share')}
text={isPinned ? translate('common.unPin') : translate('common.pin')}
/>
</View>
</View>
Expand Down
2 changes: 1 addition & 1 deletion src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ const isPolicyEmployee = (policyID: string, policies: OnyxCollection<Policy>): b
/**
* Checks if the current user is an owner (creator) of the policy.
*/
const isPolicyOwner = (policy: OnyxEntry<Policy> | EmptyObject, currentUserAccountID: number): boolean => policy?.ownerAccountID === currentUserAccountID;
const isPolicyOwner = (policy: OnyxEntry<Policy>, currentUserAccountID: number): boolean => policy?.ownerAccountID === currentUserAccountID;

/**
* Create an object mapping member emails to their accountIDs. Filter for members without errors if includeMemberWithErrors is false, and get the login email from the personalDetail object using the accountID.
Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6393,7 +6393,7 @@ function hasActionsWithErrors(reportID: string): boolean {
return Object.values(reportActions).some((action) => !isEmptyObject(action.errors));
}

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

Expand Down
76 changes: 17 additions & 59 deletions src/pages/ReportDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useRoute} from '@react-navigation/native';
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -29,7 +29,6 @@ import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as Report from '@userActions/Report';
import ConfirmModal from '@src/components/ConfirmModal';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -50,7 +49,6 @@ type ReportDetailsPageMenuItem = {
action: () => void;
brickRoadIndicator?: ValueOf<typeof CONST.BRICK_ROAD_INDICATOR_STATUS>;
subtitle?: number;
shouldShowRightIcon?: boolean;
};

type ReportDetailsPageOnyxProps = {
Expand All @@ -67,12 +65,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
const {isOffline} = useNetwork();
const styles = useThemeStyles();
const route = useRoute();
const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false);
const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? ''}`], [policies, report?.policyID]);
const isPolicyAdmin = useMemo(() => PolicyUtils.isPolicyAdmin(policy ?? null), [policy]);
const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID ?? '', policies), [report?.policyID, policies]);
const shouldUseFullTitle = useMemo(() => ReportUtils.shouldUseFullTitleToDisplay(report), [report]);
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report);
const isChatRoom = useMemo(() => ReportUtils.isChatRoom(report), [report]);
const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(report), [report]);
const isDefaultRoom = useMemo(() => ReportUtils.isDefaultRoom(report), [report]);
Expand All @@ -83,8 +79,6 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
const isInvoiceReport = useMemo(() => ReportUtils.isInvoiceReport(report), [report]);
const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(report, policy), [report, policy]);
const shouldShowReportDescription = isChatRoom && (canEditReportDescription || report.description !== '');
const canLeaveRoom = ReportUtils.canLeaveRoom(report, isPolicyEmployee);
const canLeavePolicyExpenseChat = ReportUtils.canLeavePolicyExpenseChat(report, policy ?? {});

// eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx
const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(report), [report, policy]);
Expand All @@ -105,11 +99,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
return !pendingMember || pendingMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? accountID : [];
});

const isGroupDMChat = useMemo(() => ReportUtils.isDM(report) && participants.length > 1, [report, participants.length]);
const isPrivateNotesFetchTriggered = report?.isLoadingPrivateNotes !== undefined;

const isSelfDM = useMemo(() => ReportUtils.isSelfDM(report), [report]);
const canLeave =
!isSelfDM && (isChatThread || isUserCreatedPolicyRoom || canLeaveRoom || canLeavePolicyExpenseChat) && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;

useEffect(() => {
// Do not fetch private notes if isLoadingPrivateNotes is already defined, or if the network is offline, or if the report is a self DM.
Expand All @@ -120,22 +113,23 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
Report.getReportPrivateNote(report?.reportID ?? '');
}, [report?.reportID, isOffline, isPrivateNotesFetchTriggered, isSelfDM]);

const leaveChat = useCallback(() => {
if (isChatRoom) {
const isWorkspaceMemberLeavingWorkspaceRoom = (report.visibility === CONST.REPORT.VISIBILITY.RESTRICTED || isPolicyExpenseChat) && isPolicyEmployee;
Report.leaveRoom(report.reportID, isWorkspaceMemberLeavingWorkspaceRoom);
return;
}
Report.leaveGroupChat(report.reportID);
}, [isChatRoom, isPolicyEmployee, isPolicyExpenseChat, report.reportID, report.visibility]);

const menuItems: ReportDetailsPageMenuItem[] = useMemo(() => {
const items: ReportDetailsPageMenuItem[] = [];

if (isSelfDM) {
return [];
}

if (!isGroupDMChat) {
items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.SHARE_CODE,
translationKey: 'common.shareCode',
icon: Expensicons.QrCode,
isAnonymousAction: true,
action: () => Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(report?.reportID ?? '')),
});
}

if (isArchivedRoom) {
return items;
}
Expand Down Expand Up @@ -202,27 +196,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
});
}

if (isGroupChat || (isChatRoom && canLeave)) {
items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.LEAVE_ROOM,
translationKey: 'common.leave',
icon: Expensicons.Exit,
isAnonymousAction: true,
shouldShowRightIcon: false,
action: () => {
if (Object.keys(report?.participants ?? {}).length === 1 && isGroupChat) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}

leaveChat();
},
});
}

return items;
}, [
isSelfDM,
isGroupDMChat,
isArchivedRoom,
isGroupChat,
isDefaultRoom,
Expand All @@ -232,12 +209,9 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
participants.length,
report,
isMoneyRequestReport,
isChatRoom,
canLeave,
isInvoiceReport,
activeChatMembers.length,
session,
leaveChat,
isInvoiceReport,
]);

const displayNamesWithTooltips = useMemo(() => {
Expand Down Expand Up @@ -346,10 +320,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
</View>
</View>
{shouldShowReportDescription && (
<OfflineWithFeedback
pendingAction={report.pendingFields?.description}
style={styles.mb5}
>
<OfflineWithFeedback pendingAction={report.pendingFields?.description}>
<MenuItemWithTopDescription
shouldShowRightIcon={canEditReportDescription}
interactive={canEditReportDescription}
Expand All @@ -361,7 +332,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
/>
</OfflineWithFeedback>
)}
{(isGroupChat || isChatRoom) && <ChatDetailsQuickActionsBar report={report} />}
{isGroupChat && <ChatDetailsQuickActionsBar report={report} />}
{menuItems.map((item) => {
const brickRoadIndicator =
ReportUtils.hasReportNameError(report) && item.key === CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;
Expand All @@ -373,25 +344,12 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
icon={item.icon}
onPress={item.action}
isAnonymousAction={item.isAnonymousAction}
shouldShowRightIcon={item.shouldShowRightIcon ?? true}
shouldShowRightIcon
brickRoadIndicator={brickRoadIndicator ?? item.brickRoadIndicator}
/>
);
})}
</ScrollView>
<ConfirmModal
danger
title={translate('groupChat.lastMemberTitle')}
isVisible={isLastMemberLeavingGroupModalVisible}
onConfirm={() => {
setIsLastMemberLeavingGroupModalVisible(false);
Report.leaveGroupChat(report.reportID);
}}
onCancel={() => setIsLastMemberLeavingGroupModalVisible(false)}
prompt={translate('groupChat.lastMemberWarning')}
confirmText={translate('common.leave')}
cancelText={translate('common.cancel')}
/>
</FullPageNotFoundView>
</ScreenWrapper>
);
Expand Down
Loading