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

Move Leave button into a row of the Report Details page #41823

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f245c2f
Move Leave button into a row of the Report Details page
ZhenjaHorbach May 8, 2024
43334c4
Remove condition for ChatDetailsQuickActionsBar
ZhenjaHorbach May 13, 2024
746ad28
Update branch and fix conflicts
ZhenjaHorbach May 15, 2024
ca4e3ad
Update condition for leave modal
ZhenjaHorbach May 15, 2024
d1814c1
Update dependency for menuItems
ZhenjaHorbach May 15, 2024
7c630c8
Update conditions for leave button
ZhenjaHorbach May 15, 2024
0aa0fb9
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 16, 2024
564b82f
Fix comments
ZhenjaHorbach May 16, 2024
6c53db0
Disable ActionsBar for isGroupDMChat
ZhenjaHorbach May 16, 2024
8a9c211
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 16, 2024
f6202cc
Fix comments
ZhenjaHorbach May 28, 2024
6bdf55c
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 28, 2024
37e90c7
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 28, 2024
7d6fe50
Fix ts issue
ZhenjaHorbach May 28, 2024
1c8f9d3
Fix eslint issue
ZhenjaHorbach May 28, 2024
2436d71
Move isPolicyExpenseChat
ZhenjaHorbach May 28, 2024
ec49893
Add condition for share button
ZhenjaHorbach May 28, 2024
bf1dac5
Fix conflicts and update branch
ZhenjaHorbach May 29, 2024
0b0126e
Add comment for isHidden
ZhenjaHorbach May 29, 2024
ab5a203
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 29, 2024
25a6964
Refactor types for ActionBar
ZhenjaHorbach May 29, 2024
d09d4d7
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 30, 2024
19c22bf
Fix comments
ZhenjaHorbach May 30, 2024
9f957f5
Merge branch 'main' into move-leave-button-into-row-of-the-report-det…
ZhenjaHorbach May 30, 2024
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: 0 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2086,7 +2086,6 @@ const CONST = {
INFO: 'info',
},
REPORT_DETAILS_MENU_ITEM: {
SHARE_CODE: 'shareCode',
MEMBERS: 'member',
INVITE: 'invite',
SETTINGS: 'settings',
Expand Down
40 changes: 11 additions & 29 deletions src/components/ChatDetailsQuickActionsBar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, {useState} from 'react';
import React 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 @@ -14,45 +15,26 @@ 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={() => {
if (Object.keys(report?.participants ?? {}).length === 1) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}

Report.leaveGroupChat(report.reportID);
}}
icon={Expensicons.Exit}
onPress={() => Report.togglePinnedState(report.reportID, isPinned)}
icon={Expensicons.Pin}
style={styles.flex1}
text={translate('common.leave')}
text={isPinned ? translate('common.unPin') : translate('common.pin')}
/>
</View>
<View style={[styles.flex1]}>
<Button
onPress={() => Report.togglePinnedState(report.reportID, isPinned)}
icon={Expensicons.Pin}
onPress={() => {
Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(report?.reportID ?? ''));
}}
icon={Expensicons.QrCode}
style={styles.flex1}
text={isPinned ? translate('common.unPin') : translate('common.pin')}
text={translate('common.share')}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

well, we need to add back the if (!isGroupDMChat) to this part now... I thought that was clear from my last comment sorry if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, sorry
Perhaps I misunderstood
But I fixed it
And I updated the styles for one button inside ActionsBar following this comment

#40256 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

Would you mind posting a screen shot of this change? I want to make sure it's what @shawnborton expects. Thanks!

Copy link
Contributor Author

@ZhenjaHorbach ZhenjaHorbach May 29, 2024

Choose a reason for hiding this comment

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

Something like this if we have one button
Снимок экрана 2024-05-29 в 02 56 59

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we're working on a component for this that has all of that baked in. @grgia does that sound right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Check this PR here: #41972

Just want to make sure we aren't duplicating work.

Copy link
Contributor

Choose a reason for hiding this comment

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

@shawnborton thanks for noticing! It looks like this PR will conflict with #41972

cc @grgia

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the heads up @shawnborton

I think we're good here though. We just need to fix some conflicts now @ZhenjaHorbach. I've instructed @cdOut to pause the next PR they mentioned since we don't really need it.

@grgia might want to do a quick scan to make sure there aren't any other improvements with open issues that snuck into that design doc, but don't think there are a ton. They should all be in the #vip-split project and categorized by Group Chats.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the PR and made changes to use the new implementation for ActionBar

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Although we have TS issue in main
#42798

</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 @@ -141,7 +141,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>, currentUserAccountID: number): boolean => policy?.ownerAccountID === currentUserAccountID;
const isPolicyOwner = (policy: OnyxEntry<Policy> | EmptyObject, 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
85 changes: 60 additions & 25 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, {useEffect, useMemo} from 'react';
import React, {useCallback, useEffect, useMemo, useState} 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,6 +29,7 @@ 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 @@ -49,6 +50,7 @@ type ReportDetailsPageMenuItem = {
action: () => void;
brickRoadIndicator?: ValueOf<typeof CONST.BRICK_ROAD_INDICATOR_STATUS>;
subtitle?: number;
shouldShowRightIcon?: boolean;
};

type ReportDetailsPageOnyxProps = {
Expand All @@ -65,10 +67,12 @@ 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 = useMemo(() => ReportUtils.isPolicyExpenseChat(report), [report]);
const isChatRoom = useMemo(() => ReportUtils.isChatRoom(report), [report]);
const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(report), [report]);
const isDefaultRoom = useMemo(() => ReportUtils.isDefaultRoom(report), [report]);
Expand All @@ -78,7 +82,6 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
const isMoneyRequest = useMemo(() => ReportUtils.isMoneyRequest(report), [report]);
const isInvoiceReport = useMemo(() => ReportUtils.isInvoiceReport(report), [report]);
const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(report, policy), [report, policy]);
const shouldShowReportDescription = isChatRoom && (canEditReportDescription || report.description !== '');

// 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 @@ -99,11 +102,12 @@ 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 shouldShowReportDescription = isChatRoom && (canEditReportDescription || report.description !== '');
Copy link
Contributor

Choose a reason for hiding this comment

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

Revert the position of this variable to keep the change is clean


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.
if (isPrivateNotesFetchTriggered || isOffline || isSelfDM) {
Expand All @@ -113,23 +117,22 @@ 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 @@ -159,10 +162,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
}
},
});
} else if (
(isUserCreatedPolicyRoom && (!participants.length || !isPolicyEmployee)) ||
((isDefaultRoom || ReportUtils.isPolicyExpenseChat(report)) && isChatThread && !isPolicyEmployee)
) {
} else if ((isUserCreatedPolicyRoom && (!participants.length || !isPolicyEmployee)) || ((isDefaultRoom || isPolicyExpenseChat) && isChatThread && !isPolicyEmployee)) {
items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.INVITE,
translationKey: 'common.invite',
Expand Down Expand Up @@ -196,10 +196,27 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
});
}

if ((isGroupChat || (isChatRoom && ReportUtils.canLeaveChat(report, policy ?? null))) && !isThread) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Agree with you at this point && !isThread if it is thread we should display leave row

Copy link
Contributor

Choose a reason for hiding this comment

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

Agree, but sort of out of scope for the original ticket maybe. I believe there is a separate project to make this change.

items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.LEAVE_ROOM,
translationKey: 'common.leave',
icon: Expensicons.Exit,
isAnonymousAction: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Coming from #43404:
@ZhenjaHorbach was there any reason for setting this value to true?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm
Actually good question
But I don't think it should be true

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for confirmation

shouldShowRightIcon: false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Should add shouldShowRightIcon: true to other item

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry
I probably didn't fully understand you
But we only have one place where we don't need an icon
For other cases I have added a condition here

https://github.com/Expensify/App/pull/41823/files#diff-409b0e2fb439856e9897b808014031ce244a427d116ed30f37a2e0117599adc4R369

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, the current change work well, but I think add shouldShowRightIcon: true to other item will be clearer

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahhhh
I understand )
No problem
I'll update now

action: () => {
if (Object.keys(report?.participants ?? {}).length === 1 && isGroupChat) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}

leaveChat();
},
});
}

return items;
}, [
isSelfDM,
isGroupDMChat,
isArchivedRoom,
isGroupChat,
isDefaultRoom,
Expand All @@ -208,10 +225,15 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
isUserCreatedPolicyRoom,
participants.length,
report,
isPolicyExpenseChat,
isMoneyRequestReport,
isInvoiceReport,
isThread,
isChatRoom,
policy,
activeChatMembers.length,
session,
leaveChat,
]);

const displayNamesWithTooltips = useMemo(() => {
Expand Down Expand Up @@ -258,10 +280,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
/>
);

const reportName =
ReportUtils.isDeprecatedGroupDM(report) || ReportUtils.isGroupChat(report)
? ReportUtils.getGroupChatName(undefined, false, report.reportID ?? '')
: ReportUtils.getReportName(report);
const reportName = ReportUtils.isDeprecatedGroupDM(report) || isGroupChat ? ReportUtils.getGroupChatName(undefined, false, report.reportID ?? '') : ReportUtils.getReportName(report);
return (
<ScreenWrapper testID={ReportDetailsPage.displayName}>
<FullPageNotFoundView shouldShow={isEmptyObject(report)}>
Expand Down Expand Up @@ -320,7 +339,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
</View>
</View>
{shouldShowReportDescription && (
<OfflineWithFeedback pendingAction={report.pendingFields?.description}>
<OfflineWithFeedback
pendingAction={report.pendingFields?.description}
style={styles.mb5}
>
<MenuItemWithTopDescription
shouldShowRightIcon={canEditReportDescription}
interactive={canEditReportDescription}
Expand All @@ -332,7 +354,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
/>
</OfflineWithFeedback>
)}
{isGroupChat && <ChatDetailsQuickActionsBar report={report} />}
<ChatDetailsQuickActionsBar report={report} />
Copy link
Contributor

Choose a reason for hiding this comment

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

@ZhenjaHorbach From my viewpoint, we should update like this

Suggested change
<ChatDetailsQuickActionsBar report={report} />
{!isGroupDMChat && <ChatDetailsQuickActionsBar report={report} />}

To make sure the logic to display the share button is same like before

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will update this line
If something happens, I'll revert the last commit
If we decide to use it everywhere

{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 @@ -344,12 +366,25 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
icon={item.icon}
onPress={item.action}
isAnonymousAction={item.isAnonymousAction}
shouldShowRightIcon
shouldShowRightIcon={item.shouldShowRightIcon ?? true}
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