diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 5f426f77b731..e89026137b67 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -116,7 +116,7 @@ function ButtonWithDropdownMenu({ success={success} ref={buttonRef} pressOnEnter={pressOnEnter} - isDisabled={isDisabled} + isDisabled={isDisabled || !!options[0].disabled} style={[styles.w100, style]} isLoading={isLoading} text={selectedItem.text} diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 83100788761f..87db9a29d827 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -22,6 +22,7 @@ type DropdownOption = { iconHeight?: number; iconDescription?: string; onSelected?: () => void; + disabled?: boolean; }; type ButtonWithDropdownMenuProps = { diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 2bf346ec8de4..9c3d9b8640e7 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -67,9 +67,12 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(moneyRequestReport, chatReport, policy), [moneyRequestReport, chatReport, policy]); + const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport); + const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; + const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; const shouldShowNextStep = !ReportUtils.isClosedExpenseReportWithNoExpenses(moneyRequestReport) && isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; @@ -121,6 +124,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} + shouldDisableApproveButton={shouldDisableApproveButton} style={[styles.pv2]} formattedAmount={formattedAmount} isDisabled={!canAllowSettlement} @@ -135,6 +139,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money text={translate('common.submit')} style={[styles.mnw120, styles.pv2, styles.pr0]} onPress={() => IOU.submitReport(moneyRequestReport)} + isDisabled={shouldDisableSubmitButton} /> )} @@ -153,6 +158,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} + shouldDisableApproveButton={shouldDisableApproveButton} formattedAmount={formattedAmount} isDisabled={!canAllowSettlement} /> @@ -166,6 +172,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money text={translate('common.submit')} style={[styles.w100, styles.pr0]} onPress={() => IOU.submitReport(moneyRequestReport)} + isDisabled={shouldDisableSubmitButton} /> )} diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 44a446b56653..8f54de5182f8 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -24,6 +24,9 @@ type PopoverMenuItem = MenuItemProps & { /** Sub menu items to be rendered after a menu item is selected */ subMenuItems?: PopoverMenuItem[]; + + /** Determines whether the menu item is disabled or not */ + disabled?: boolean; }; type PopoverModalProps = Pick; @@ -205,6 +208,7 @@ function PopoverMenu({ displayInDefaultIconColor={item.displayInDefaultIconColor} shouldShowRightIcon={item.shouldShowRightIcon} shouldPutLeftPaddingWhenNoIcon={item.shouldPutLeftPaddingWhenNoIcon} + disabled={item.disabled} /> ))} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index d183d27fefb8..b843443be4af 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -153,6 +153,7 @@ function ReportPreview({ }); const shouldShowSubmitButton = isOpenExpenseReport && reimbursableSpend !== 0; + const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport); // The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on const isWaitingForSubmissionFromCurrentUser = useMemo( @@ -209,6 +210,8 @@ function ReportPreview({ const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(iouReport, chatReport, policy), [iouReport, chatReport, policy]); + const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); + const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldPromptUserToAddBankAccount = ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID); @@ -307,6 +310,7 @@ function ReportPreview({ addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} shouldShowApproveButton={shouldShowApproveButton} + shouldDisableApproveButton={shouldDisableApproveButton} kycWallAnchorAlignment={{ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, @@ -324,6 +328,7 @@ function ReportPreview({ success={isWaitingForSubmissionFromCurrentUser} text={translate('common.submit')} onPress={() => iouReport && IOU.submitReport(iouReport)} + isDisabled={shouldDisableSubmitButton} /> )} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 6b6ad3af737a..0ea8ea308d6a 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -60,6 +60,9 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** Should we show the payment options? */ shouldShowApproveButton?: boolean; + /** Should approve button be disabled? */ + shouldDisableApproveButton?: boolean; + /** The policyID of the report we are paying */ policyID?: string; @@ -124,6 +127,7 @@ function SettlementButton({ policyID = '', shouldHidePaymentOptions = false, shouldShowApproveButton = false, + shouldDisableApproveButton = false, style, shouldShowPersonalBankAccountOption = false, enterKeyEventListenerPriority = 0, @@ -166,6 +170,7 @@ function SettlementButton({ text: translate('iou.approve'), icon: Expensicons.ThumbsUp, value: CONST.IOU.REPORT_ACTION_TYPE.APPROVE, + disabled: !!shouldDisableApproveButton, }; const canUseWallet = !isExpenseReport && currency === CONST.CURRENCY.USD; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 705f1fd38367..d0ce53a0e10b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5448,6 +5448,22 @@ function canBeAutoReimbursed(report: OnyxEntry, policy: OnyxEntry, approverAccountID?: number): boolean { + const policy = getPolicy(report?.policyID); + const {preventSelfApproval} = policy; + + const isOwner = (approverAccountID ?? currentUserAccountID) === report?.ownerAccountID; + + return !(preventSelfApproval && isOwner); +} + +function isAllowedToSubmitDraftExpenseReport(report: OnyxEntry): boolean { + const policy = getPolicy(report?.policyID); + const {submitsTo} = policy; + + return isAllowedToApproveExpenseReport(report, submitsTo); +} + /** * What missing payment method does this report action indicate, if any? */ @@ -5700,6 +5716,8 @@ export { canEditRoomVisibility, canEditPolicyDescription, getPolicyDescriptionText, + isAllowedToSubmitDraftExpenseReport, + isAllowedToApproveExpenseReport, findSelfDMReportID, getIndicatedMissingPaymentMethod, isJoinRequestInAdminRoom,