Skip to content

Commit

Permalink
Merge pull request #44025 from software-mansion-labs/@cdOut/three-dot…
Browse files Browse the repository at this point in the history
…-removal

[Details Revamp] Remove the Three Dot Menu on Affected Reports
  • Loading branch information
grgia authored Jul 5, 2024
2 parents 87f5cdd + 2a7a161 commit 7f98594
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 263 deletions.
71 changes: 1 addition & 70 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as HeaderUtils from '@libs/HeaderUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
Expand All @@ -22,7 +21,6 @@ import ROUTES from '@src/ROUTES';
import type {Route} from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import Button from './Button';
Expand Down Expand Up @@ -86,28 +84,20 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
const [shouldShowHoldMenu, setShouldShowHoldMenu] = useState(false);
const {translate} = useLocalize();
const {isOffline} = useNetwork();
const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
const {isSmallScreenWidth} = useWindowDimensions();
const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(moneyRequestReport);
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);
const isApproved = ReportUtils.isReportApproved(moneyRequestReport);
const isClosed = ReportUtils.isClosedReport(moneyRequestReport);
const isOnHold = TransactionUtils.isOnHold(transaction);
const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
const isDeletedParentAction = !!requestParentReportAction && ReportActionsUtils.isDeletedAction(requestParentReportAction);
const canHoldOrUnholdRequest = !isEmptyObject(transaction) && !isSettled && !isApproved && !isDeletedParentAction && !isClosed;

// Only the requestor can delete the request, admins can only edit it.
const isActionOwner =
typeof requestParentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && requestParentReportAction.actorAccountID === session?.accountID;
const canDeleteRequest = isActionOwner && ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) && !isDeletedParentAction;
const isPolicyAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN;
const isApprover = ReportUtils.isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && session?.accountID === moneyRequestReport?.managerID;
const [isHoldMenuVisible, setIsHoldMenuVisible] = useState(false);
const [paymentType, setPaymentType] = useState<PaymentMethodType>();
const [requestType, setRequestType] = useState<ActionHandledType>();
const canAllowSettlement = ReportUtils.hasUpdatedTotal(moneyRequestReport, policy);
const policyType = policy?.type;
const isPayer = ReportUtils.isPayer(session, moneyRequestReport);
const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport);
const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);

Expand Down Expand Up @@ -198,22 +188,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
TransactionActions.markAsCash(iouTransactionID, reportID);
}, [requestParentReportAction, transactionThreadReport?.reportID]);

const changeMoneyRequestStatus = () => {
if (!transactionThreadReport) {
return;
}
const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(requestParentReportAction)
? ReportActionsUtils.getOriginalMessage(requestParentReportAction)?.IOUTransactionID ?? '-1'
: '-1';

if (isOnHold) {
IOU.unholdRequest(iouTransactionID, transactionThreadReport.reportID);
} else {
const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams());
Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy?.type ?? CONST.POLICY.TYPE.PERSONAL, iouTransactionID, transactionThreadReport.reportID, activeRoute));
}
};

const getStatusIcon: (src: IconAsset) => React.ReactNode = (src) => (
<Icon
src={src}
Expand Down Expand Up @@ -243,29 +217,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
[chatReport?.isOwnPolicyExpenseChat, policy?.harvesting?.enabled],
);

const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(moneyRequestReport)];
if (canHoldOrUnholdRequest) {
const isRequestIOU = ReportUtils.isIOUReport(chatReport);
const isHoldCreator = ReportUtils.isHoldCreator(transaction, moneyRequestReport?.reportID) && isRequestIOU;
const isTrackExpenseReport = ReportUtils.isTrackExpenseReport(moneyRequestReport);
const canModifyStatus = !isTrackExpenseReport && (isPolicyAdmin || isActionOwner || isApprover);
const isInvoiceReport = ReportUtils.isInvoiceReport(moneyRequestReport);
if (isOnHold && (isHoldCreator || (!isRequestIOU && canModifyStatus)) && !isInvoiceReport) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.unholdExpense'),
onSelected: () => changeMoneyRequestStatus(),
});
}
if (!isOnHold && (isRequestIOU || canModifyStatus) && !isScanning && !isInvoiceReport) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.hold'),
onSelected: () => changeMoneyRequestStatus(),
});
}
}

useEffect(() => {
if (isLoadingHoldUseExplained) {
return;
Expand All @@ -291,23 +242,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
IOU.dismissHoldUseExplanation();
};

if (isPayer && isSettled && ReportUtils.isExpenseReport(moneyRequestReport)) {
threeDotsMenuItems.push({
icon: Expensicons.Trashcan,
text: translate('iou.cancelPayment'),
onSelected: () => setIsConfirmModalVisible(true),
});
}

// If the report supports adding transactions to it, then it also supports deleting transactions from it.
if (canDeleteRequest && !isEmptyObject(transactionThreadReport)) {
threeDotsMenuItems.push({
icon: Expensicons.Trashcan,
text: translate('reportActionContextMenu.deleteAction', {action: requestParentReportAction}),
onSelected: () => setIsDeleteRequestModalVisible(true),
});
}

useEffect(() => {
if (canDeleteRequest) {
return;
Expand All @@ -328,9 +262,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
onBackButtonPress={onBackButtonPress}
// Shows border if no buttons or banners are showing below the header
shouldShowBorderBottom={!isMoreContentShown}
shouldShowThreeDotsButton
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
>
{shouldShowSettlementButton && !shouldUseNarrowLayout && (
<View style={styles.pv2}>
Expand Down
100 changes: 2 additions & 98 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import type {ReactNode} from 'react';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import React, {useCallback, useEffect, useState} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as HeaderUtils from '@libs/HeaderUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import * as TransactionActions from '@userActions/Transaction';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Route} from '@src/ROUTES';
import type {Policy, Report, ReportAction} from '@src/types/onyx';
import type IconAsset from '@src/types/utils/IconAsset';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
Expand Down Expand Up @@ -56,67 +52,28 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
}`,
);
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [dismissedHoldUseExplanation, dismissedHoldUseExplanationResult] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {initialValue: true});
const isLoadingHoldUseExplained = isLoadingOnyxValue(dismissedHoldUseExplanationResult);
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
const [shouldShowHoldMenu, setShouldShowHoldMenu] = useState(false);
const isSelfDMTrackExpenseReport = ReportUtils.isTrackExpenseReport(report) && ReportUtils.isSelfDM(parentReport);
const moneyRequestReport = !isSelfDMTrackExpenseReport ? parentReport : undefined;
const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID);
const isApproved = ReportUtils.isReportApproved(moneyRequestReport);
const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport);
const isOnHold = TransactionUtils.isOnHold(transaction);
const isDuplicate = TransactionUtils.isDuplicate(transaction?.transactionID ?? '');
const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
const {isSmallScreenWidth} = useWindowDimensions();

const navigateBackToAfterDelete = useRef<Route>();

// Only the requestor can take delete the request, admins can only edit it.
const isActionOwner = typeof parentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && parentReportAction.actorAccountID === session?.accountID;
const isPolicyAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN;
const isApprover = ReportUtils.isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && session?.accountID === moneyRequestReport?.managerID;
const hasAllPendingRTERViolations = TransactionUtils.allHavePendingRTERViolation([transaction?.transactionID ?? '-1']);
const shouldShowMarkAsCashButton = isDraft && hasAllPendingRTERViolations;
const deleteTransaction = useCallback(() => {
if (parentReportAction) {
const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1';
if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) {
navigateBackToAfterDelete.current = IOU.deleteTrackExpense(parentReport?.reportID ?? '-1', iouTransactionID, parentReportAction, true);
} else {
navigateBackToAfterDelete.current = IOU.deleteMoneyRequest(iouTransactionID, parentReportAction, true);
}
}

setIsDeleteModalVisible(false);
}, [parentReport?.reportID, parentReportAction, setIsDeleteModalVisible]);

const markAsCash = useCallback(() => {
TransactionActions.markAsCash(transaction?.transactionID ?? '-1', report.reportID);
}, [report.reportID, transaction?.transactionID]);

const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);

const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction);
const canHoldOrUnholdRequest = !isSettled && !isApproved && !isDeletedParentAction && !ReportUtils.isArchivedRoom(parentReport);

// If the report supports adding transactions to it, then it also supports deleting transactions from it.
const canDeleteRequest = isActionOwner && (ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction;

const changeMoneyRequestStatus = () => {
const iouTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1';

if (isOnHold) {
IOU.unholdRequest(iouTransactionID, report?.reportID);
} else {
const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams());
Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy?.type ?? CONST.POLICY.TYPE.PERSONAL, iouTransactionID, report?.reportID, activeRoute));
}
};

const getStatusIcon: (src: IconAsset) => ReactNode = (src) => (
<Icon
src={src}
Expand Down Expand Up @@ -144,36 +101,6 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow

const statusBarProps = getStatusBarProps();

useEffect(() => {
if (canDeleteRequest) {
return;
}

setIsDeleteModalVisible(false);
}, [canDeleteRequest]);

const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(report)];
if (canHoldOrUnholdRequest) {
const isRequestIOU = parentReport?.type === 'iou';
const isHoldCreator = ReportUtils.isHoldCreator(transaction, report?.reportID) && isRequestIOU;
const isTrackExpenseReport = ReportUtils.isTrackExpenseReport(report);
const canModifyStatus = !isTrackExpenseReport && (isPolicyAdmin || isActionOwner || isApprover);
if (isOnHold && !isDuplicate && (isHoldCreator || (!isRequestIOU && canModifyStatus))) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.unholdExpense'),
onSelected: () => changeMoneyRequestStatus(),
});
}
if (!isOnHold && (isRequestIOU || canModifyStatus) && !isScanning) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.hold'),
onSelected: () => changeMoneyRequestStatus(),
});
}
}

useEffect(() => {
if (isLoadingHoldUseExplained) {
return;
Expand All @@ -199,14 +126,6 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
IOU.dismissHoldUseExplanation();
};

if (canDeleteRequest) {
threeDotsMenuItems.push({
icon: Expensicons.Trashcan,
text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}),
onSelected: () => setIsDeleteModalVisible(true),
});
}

return (
<>
<View style={[styles.pl0]}>
Expand All @@ -215,9 +134,6 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
shouldShowReportAvatarWithDisplay
shouldEnableDetailPageNavigation
shouldShowPinButton={false}
shouldShowThreeDotsButton
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
report={{
...report,
ownerAccountID: parentReport?.ownerAccountID,
Expand Down Expand Up @@ -281,18 +197,6 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
</View>
)}
</View>
<ConfirmModal
title={translate('iou.deleteExpense')}
isVisible={isDeleteModalVisible}
onConfirm={deleteTransaction}
onCancel={() => setIsDeleteModalVisible(false)}
onModalHide={() => ReportUtils.navigateBackAfterDeleteTransaction(navigateBackToAfterDelete.current)}
prompt={translate('iou.deleteConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
danger
shouldEnableNewFocusManagement
/>
{isSmallScreenWidth && shouldShowHoldMenu && (
<ProcessMoneyRequestHoldMenu
onClose={handleHoldRequestClose}
Expand Down
16 changes: 16 additions & 0 deletions src/pages/ProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as UserUtils from '@libs/UserUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
import type {ProfileNavigatorParamList} from '@navigation/types';
import * as LinkActions from '@userActions/Link';
import * as PersonalDetailsActions from '@userActions/PersonalDetails';
import * as ReportActions from '@userActions/Report';
import * as SessionActions from '@userActions/Session';
Expand Down Expand Up @@ -79,6 +80,9 @@ function ProfilePage({route}: ProfilePageProps) {
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_METADATA);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [guideCalendarLink] = useOnyx(ONYXKEYS.ACCOUNT, {
selector: (account) => account?.guideCalendarLink,
});

const reportKey = useMemo(() => {
const accountID = Number(route.params?.accountID ?? -1);
Expand Down Expand Up @@ -175,6 +179,8 @@ function ProfilePage({route}: ProfilePageProps) {
return result;
}, [accountID, isCurrentUser, loginParams, report]);

const isConcierge = ReportUtils.isConciergeChatReport(report);

return (
<ScreenWrapper testID={ProfilePage.displayName}>
<FullPageNotFoundView shouldShow={shouldShowBlockingView}>
Expand Down Expand Up @@ -276,6 +282,16 @@ function ProfilePage({route}: ProfilePageProps) {
brickRoadIndicator={ReportActions.hasErrorInPrivateNotes(report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
/>
)}
{isConcierge && guideCalendarLink && (
<MenuItem
title={translate('videoChatButtonAndMenu.tooltip')}
icon={Expensicons.Phone}
isAnonymousAction={false}
onPress={SessionActions.checkIfActionIsAllowed(() => {
LinkActions.openExternalLink(guideCalendarLink);
})}
/>
)}
</ScrollView>
{!hasAvatar && isLoading && <FullScreenLoadingIndicator style={styles.flex1} />}
</View>
Expand Down
Loading

0 comments on commit 7f98594

Please sign in to comment.