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

[Held requests] Hold button on expense preview appears only if open the expense first #51354

Closed
Closed
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
13 changes: 13 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3275,6 +3275,18 @@ const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry<ReportAction>, bac
}
};

function changePreviewHoldStatus(isOnHold: boolean, transactionID: string, reportID: string): void {
const report = getReport(reportID ?? '-1');
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`] ?? null;

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

/**
* Gets all transactions on an IOU report with a receipt
*/
Expand Down Expand Up @@ -8609,6 +8621,7 @@ export {
isCurrentUserInvoiceReceiver,
isDraftReport,
changeMoneyRequestHoldStatus,
changePreviewHoldStatus,
isAdminOwnerApproverOrReportOwner,
createDraftWorkspaceAndNavigateToConfirmationScreen,
isChatUsedForOnboarding,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import useEnvironment from '@hooks/useEnvironment';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
Expand Down Expand Up @@ -143,43 +142,6 @@ function BaseReportActionContextMenu({

const [download] = useOnyx(`${ONYXKEYS.COLLECTION.DOWNLOAD}${sourceID}`);

const childReport = ReportUtils.getReport(reportAction?.childReportID ?? '-1');
const parentReportAction = ReportActionsUtils.getReportAction(childReport?.parentReportID ?? '', childReport?.parentReportActionID ?? '');
const {reportActions: paginatedReportActions} = usePaginatedReportActions(childReport?.reportID ?? '-1');

const transactionThreadReportID = useMemo(
() => ReportActionsUtils.getOneTransactionThreadReportID(childReport?.reportID ?? '-1', paginatedReportActions ?? [], isOffline),
[childReport?.reportID, paginatedReportActions, isOffline],
);

const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);

const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(childReport), [childReport]);
const isInvoiceReport = useMemo(() => ReportUtils.isInvoiceReport(childReport), [childReport]);

const requestParentReportAction = useMemo(() => {
if (isMoneyRequestReport || isInvoiceReport) {
if (!paginatedReportActions || !transactionThreadReport?.parentReportActionID) {
return undefined;
}
return paginatedReportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID);
}
return parentReportAction;
}, [parentReportAction, isMoneyRequestReport, isInvoiceReport, paginatedReportActions, transactionThreadReport?.parentReportActionID]);

const moneyRequestAction = transactionThreadReportID ? requestParentReportAction : parentReportAction;

const [parentReportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${childReport?.parentReportID ?? '-1'}`);
const parentReport = ReportUtils.getReport(childReport?.parentReportID ?? '-1');

const isMoneyRequest = useMemo(() => ReportUtils.isMoneyRequest(childReport), [childReport]);
const isTrackExpenseReport = ReportUtils.isTrackExpenseReport(childReport);
const isSingleTransactionView = isMoneyRequest || isTrackExpenseReport;
const isMoneyRequestOrReport = isMoneyRequestReport || isSingleTransactionView;

const areHoldRequirementsMet =
!isInvoiceReport && isMoneyRequestOrReport && !ReportUtils.isArchivedRoom(transactionThreadReportID ? childReport : parentReport, parentReportNameValuePairs);

const shouldEnableArrowNavigation = !isMini && (isVisible || shouldKeepOpen);
let filteredContextMenuActions = ContextMenuActions.filter(
(contextAction) =>
Expand All @@ -197,8 +159,6 @@ function BaseReportActionContextMenu({
isOffline: !!isOffline,
isMini,
isProduction,
moneyRequestAction,
areHoldRequirementsMet,
user,
}),
);
Expand Down Expand Up @@ -319,7 +279,6 @@ function BaseReportActionContextMenu({
interceptAnonymousUser,
openOverflowMenu,
setIsEmojiPickerActive,
moneyRequestAction,
hasCard: !!card,
};

Expand Down
39 changes: 26 additions & 13 deletions src/pages/home/report/ContextMenu/ContextMenuActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ type ShouldShow = (args: {
isOffline: boolean;
isMini: boolean;
isProduction: boolean;
moneyRequestAction: ReportAction | undefined;
areHoldRequirementsMet: boolean;
user: OnyxEntry<User>;
}) => boolean;

Expand All @@ -87,7 +85,6 @@ type ContextMenuActionPayload = {
event?: GestureResponderEvent | MouseEvent | KeyboardEvent;
setIsEmojiPickerActive?: (state: boolean) => void;
anchorRef?: MutableRefObject<View | null>;
moneyRequestAction: ReportAction | undefined;
hasCard?: boolean;
};

Expand Down Expand Up @@ -267,33 +264,49 @@ const ContextMenuActions: ContextMenuAction[] = [
isAnonymousAction: false,
textTranslateKey: 'iou.unhold',
icon: Expensicons.Stopwatch,
shouldShow: ({type, moneyRequestAction, areHoldRequirementsMet}) =>
type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && ReportUtils.canHoldUnholdReportAction(moneyRequestAction).canUnholdRequest,
onPress: (closePopover, {moneyRequestAction}) => {
shouldShow: ({type, reportAction}) => {
const areHoldRequirementsMet = !!reportAction?.childHoldData;
const isOnHold = !!reportAction?.childHoldData?.isOnHold;

return type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && !isOnHold;
},
onPress: (closePopover, {reportAction}) => {
const isOnHold = !!reportAction?.childHoldData?.isOnHold;
const transactionID = reportAction.childHoldData?.transactionID ?? '-1';
const reportID = reportAction.childHoldData?.reportID ?? '-1';

if (closePopover) {
hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction));
hideContextMenu(false, () => ReportUtils.changePreviewHoldStatus(isOnHold, transactionID, reportID));
return;
}

// No popover to hide, call changeMoneyRequestHoldStatus immediately
ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction);
ReportUtils.changePreviewHoldStatus(isOnHold, transactionID, reportID);
},
getDescription: () => {},
},
{
isAnonymousAction: false,
textTranslateKey: 'iou.hold',
icon: Expensicons.Stopwatch,
shouldShow: ({type, moneyRequestAction, areHoldRequirementsMet}) =>
type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && ReportUtils.canHoldUnholdReportAction(moneyRequestAction).canHoldRequest,
onPress: (closePopover, {moneyRequestAction}) => {
shouldShow: ({type, reportAction}) => {
const areHoldRequirementsMet = !!reportAction?.childHoldData;
const isOnHold = !!reportAction?.childHoldData?.isOnHold;

return type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && areHoldRequirementsMet && isOnHold;
},
onPress: (closePopover, {reportAction}) => {
const isOnHold = !!reportAction?.childHoldData?.isOnHold;
const transactionID = reportAction.childHoldData?.transactionID ?? '-1';
const reportID = reportAction.childHoldData?.reportID ?? '-1';

if (closePopover) {
hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction));
hideContextMenu(false, () => ReportUtils.changePreviewHoldStatus(isOnHold, transactionID, reportID));
return;
}

// No popover to hide, call changeMoneyRequestHoldStatus immediately
ReportUtils.changeMoneyRequestHoldStatus(moneyRequestAction);
ReportUtils.changePreviewHoldStatus(isOnHold, transactionID, reportID);
},
getDescription: () => {},
},
Expand Down
15 changes: 15 additions & 0 deletions src/types/onyx/ReportAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ type Person = {
text?: string;
};

/** Model of data required for hold */
type HoldData = {
/** Is currently held */
isOnHold?: boolean;

/** ID of held transaction */
transactionID?: string;

/** ID of held report */
reportID?: string;
};

/** Main properties of report action */
type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{
/** The ID of the reportAction. It is the string representation of the a 64-bit integer. */
Expand Down Expand Up @@ -213,6 +225,9 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{
/** Amount of money requests */
childMoneyRequestCount?: number;

/** Hold data tied to report action */
childHoldData?: HoldData;

/** Whether the report action is the first one */
isFirstItem?: boolean;

Expand Down
Loading