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

feat: [Held requests] option does not show in the preview overflow menu. #42034

Merged
merged 13 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
95 changes: 87 additions & 8 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,14 @@ function isReportFieldOfTypeTitle(reportField: OnyxEntry<PolicyReportField>): bo
return reportField?.type === 'formula' && reportField?.fieldID === CONST.REPORT_FIELD_TITLE_FIELD_ID;
}

/**
* Check if Report has any held expenses
*/
function isHoldCreator(transaction: OnyxEntry<Transaction>, reportID: string): boolean {
const holdReportAction = ReportActionsUtils.getReportAction(reportID, `${transaction?.comment?.hold ?? ''}`);
return isActionCreator(holdReportAction);
}

/**
* Check if report fields are available to use in a report
*/
Expand Down Expand Up @@ -2707,6 +2715,83 @@ function canEditReportAction(reportAction: OnyxEntry<ReportAction>): boolean {
);
}

function getParentReportAction(parentReportActions: ReportActions | null | undefined, parentReportActionID: string | undefined): ReportAction | null {
robertjchen marked this conversation as resolved.
Show resolved Hide resolved
if (!parentReportActions || !parentReportActionID) {
return null;
}
return parentReportActions[parentReportActionID ?? '0'];
}

function canHoldUnholdReportAction(reportAction: OnyxEntry<ReportAction>): {canHoldRequest: boolean; canUnholdRequest: boolean} {
if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) {
return {canHoldRequest: false, canUnholdRequest: false};
}
const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0;

if (!moneyRequestReportID) {
return {canHoldRequest: false, canUnholdRequest: false};
}

const moneyRequestReport = getReport(String(moneyRequestReportID));

if (!moneyRequestReport) {
return {canHoldRequest: false, canUnholdRequest: false};
}
robertjchen marked this conversation as resolved.
Show resolved Hide resolved

const isRequestSettled = isSettled(moneyRequestReport?.reportID);
const isApproved = isReportApproved(moneyRequestReport);
const transactionID = moneyRequestReport ? reportAction?.originalMessage?.IOUTransactionID : 0;
const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction);
const parentReportActionsKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${moneyRequestReport.parentReportID}`;
const parentReportActions = allReportActions?.[parentReportActionsKey];
const parentReport = getReport(String(moneyRequestReport.parentReportID));
const parentReportAction = getParentReportAction(parentReportActions, moneyRequestReport?.parentReportActionID);

const isRequestIOU = parentReport?.type === 'iou';
const isRequestHoldCreator = isHoldCreator(transaction, moneyRequestReport?.reportID) && isRequestIOU;
const isTrackExpenseMoneyReport = isTrackExpenseReport(moneyRequestReport);
const isActionOwner =
typeof parentReportAction?.actorAccountID === 'number' &&
typeof currentUserPersonalDetails?.accountID === 'number' &&
parentReportAction.actorAccountID === currentUserPersonalDetails?.accountID;
const isApprover = isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && currentUserPersonalDetails?.accountID === moneyRequestReport?.managerID;
const isOnHold = TransactionUtils.isOnHold(transaction);
const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);

const canModifyStatus = !isTrackExpenseMoneyReport && (isPolicyAdmin || isActionOwner || isApprover);
const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction);

const canHoldOrUnholdRequest = !isRequestSettled && !isApproved && !isDeletedParentAction;
const canHoldRequest = canHoldOrUnholdRequest && !isOnHold && (isRequestHoldCreator || (!isRequestIOU && canModifyStatus)) && !isScanning;
const canUnholdRequest = Boolean(canHoldOrUnholdRequest && isOnHold && (isRequestHoldCreator || (!isRequestIOU && canModifyStatus)));

return {canHoldRequest, canUnholdRequest};
}

const changeMoneyRequestHoldStatus = (reportAction: OnyxEntry<ReportAction>): void => {
if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) {
return;
}
const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0;

const moneyRequestReport = getReport(String(moneyRequestReportID));
if (!moneyRequestReportID || !moneyRequestReport) {
return;
}
Comment on lines +2774 to +2782
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we merge these 2 conditions?

if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU || !moneyRequestReportID || !moneyRequestReport) {
return;
}

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 think thats fine, reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU check is required before defining moneyRequestReport or moneyRequestReportID.


const transactionID = reportAction?.originalMessage?.IOUTransactionID ?? '';
const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? ({} as Transaction);
const isOnHold = TransactionUtils.isOnHold(transaction);
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport.policyID}`] ?? null;

if (isOnHold) {
IOU.unholdRequest(transactionID, reportAction.childReportID ?? '');
Copy link
Contributor

Choose a reason for hiding this comment

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

In here, you updated the hold expense with its childReportID, in our BE we didn't send Pusher event to update its parent that's why our replies didn't increase when you held the expense.

Copy link
Contributor

Choose a reason for hiding this comment

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

This seems that we will need BE changes here cc @robertjchen.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@hungvu193, thanks a lot for looking into this, I agree with you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, so the backend should also push updates for the parent report here, is that correct?

Could you let me know which particular field changes in the parent report that makes the update from the backend necessary? 👀

Copy link
Contributor

Choose a reason for hiding this comment

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

childVisibleActionCount is the current field to count the replies.
Since we also added a comment when we held request, I think the pusher event will be exactly the same when we added a new comment inside a thread.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it, we can investigate- can this PR go out ahead of the backend changes or is it blocked until that field is available?

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 can go ahead with this PR first, but let's leave a note for QA team that the issue about counting replies will be fixed once BE PR is deployed.

} else {
const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams());
Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy?.type ?? CONST.POLICY.TYPE.PERSONAL, transactionID, reportAction.childReportID ?? '', activeRoute));
}
};

/**
* Gets all transactions on an IOU report with a receipt
*/
Expand Down Expand Up @@ -6210,14 +6295,6 @@ function navigateToPrivateNotes(report: OnyxEntry<Report>, session: OnyxEntry<Se
Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(report.reportID));
}

/**
* Check if Report has any held expenses
*/
function isHoldCreator(transaction: OnyxEntry<Transaction>, reportID: string): boolean {
const holdReportAction = ReportActionsUtils.getReportAction(reportID, `${transaction?.comment?.hold ?? ''}`);
return isActionCreator(holdReportAction);
}

/**
* Get all held transactions of a iouReport
*/
Expand Down Expand Up @@ -6721,6 +6798,7 @@ export {
canCreateTaskInReport,
canCurrentUserOpenReport,
canDeleteReportAction,
canHoldUnholdReportAction,
canEditFieldOfMoneyRequest,
canEditMoneyRequest,
canEditPolicyDescription,
Expand Down Expand Up @@ -6940,6 +7018,7 @@ export {
shouldShowMerchantColumn,
isCurrentUserInvoiceReceiver,
isDraftReport,
changeMoneyRequestHoldStatus,
createDraftWorkspaceAndNavigateToConfirmationScreen,
};

Expand Down
36 changes: 36 additions & 0 deletions src/pages/home/report/ContextMenu/ContextMenuActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,42 @@ const ContextMenuActions: ContextMenuAction[] = [
},
getDescription: () => {},
},
{
isAnonymousAction: false,
textTranslateKey: 'iou.unholdExpense',
icon: Expensicons.Stopwatch,
shouldShow: (type, reportAction) =>
type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canEditReportAction(reportAction) && ReportUtils.canHoldUnholdReportAction(reportAction).canUnholdRequest,
onPress: (closePopover, {reportAction}) => {
// const hold=ReportUtils.changeMoneyRequestHoldStatus().
Krishna2323 marked this conversation as resolved.
Show resolved Hide resolved
if (closePopover) {
hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(reportAction));
return;
}

// No popover to hide, call changeMoneyRequestHoldStatus immediately
ReportUtils.changeMoneyRequestHoldStatus(reportAction);
},
getDescription: () => {},
},
{
isAnonymousAction: false,
textTranslateKey: 'iou.hold',
icon: Expensicons.Stopwatch,
shouldShow: (type, reportAction) =>
type === CONST.CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canEditReportAction(reportAction) && ReportUtils.canHoldUnholdReportAction(reportAction).canHoldRequest,
onPress: (closePopover, {reportAction}) => {
// const hold=ReportUtils.changeMoneyRequestHoldStatus().
Krishna2323 marked this conversation as resolved.
Show resolved Hide resolved
if (closePopover) {
hideContextMenu(false, () => ReportUtils.changeMoneyRequestHoldStatus(reportAction));
return;
}

// No popover to hide, call changeMoneyRequestHoldStatus immediately
ReportUtils.changeMoneyRequestHoldStatus(reportAction);
},
getDescription: () => {},
},
{
isAnonymousAction: false,
textTranslateKey: 'reportActionContextMenu.joinThread',
Expand Down
Loading