diff --git a/src/components/Tables/WorkspaceListTable/LeaveWorkspaceFlow.tsx b/src/components/Tables/WorkspaceListTable/LeaveWorkspaceFlow.tsx index 6bcfe76e9dbc..0cd4b6eb5221 100644 --- a/src/components/Tables/WorkspaceListTable/LeaveWorkspaceFlow.tsx +++ b/src/components/Tables/WorkspaceListTable/LeaveWorkspaceFlow.tsx @@ -2,6 +2,7 @@ import {ModalActions} from '@components/Modal/Global/ModalContext'; import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useIsApproverOfOutstandingPolicyReports from '@hooks/useIsApproverOfOutstandingPolicyReports'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -40,6 +41,7 @@ function LeaveWorkspaceFlow({policyID, onDismiss}: LeaveWorkspaceFlowProps) { const [policy, policyResult] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); const ownerAccountID = policy?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID; const [policyOwnerDisplayName] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: ownerDisplayNameSelector(ownerAccountID)}); + const isApproverOfOutstandingReports = useIsApproverOfOutstandingPolicyReports(policyID); const isLoadingData = isLoadingOnyxValue(policyResult); @@ -53,7 +55,7 @@ function LeaveWorkspaceFlow({policyID, onDismiss}: LeaveWorkspaceFlowProps) { close(() => { const userLogin = currentUserPersonalDetails.login ?? ''; - const prompt = getLeaveWorkspaceConfirmationPrompt(policy, userLogin, policyOwnerDisplayName ?? '', translate); + const prompt = getLeaveWorkspaceConfirmationPrompt(policy, userLogin, policyOwnerDisplayName ?? '', translate, isApproverOfOutstandingReports); if (policy?.achAccount?.reimburser === userLogin) { showConfirmModal({ title: policy?.name ? translate('common.leaveWorkspaceTitle', policy.name) : translate('common.leaveWorkspace'), diff --git a/src/hooks/useIsApproverOfOutstandingPolicyReports.ts b/src/hooks/useIsApproverOfOutstandingPolicyReports.ts new file mode 100644 index 000000000000..b64a41db6974 --- /dev/null +++ b/src/hooks/useIsApproverOfOutstandingPolicyReports.ts @@ -0,0 +1,23 @@ +import {isApproverOfOutstandingPolicyReports} from '@libs/ReportUtils'; + +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; +import useOnyx from './useOnyx'; +import usePrivateIsArchivedMap from './usePrivateIsArchivedMap'; + +/** + * Whether the current user is the approver of any report in the workspace that is waiting for their approval, + * including the ones they were assigned to through "Change approver". + */ +function useIsApproverOfOutstandingPolicyReports(policyID: string | undefined): boolean { + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + // Subscribing without a selector keeps the change detection a reference compare, and the reports are reduced to a boolean below. + const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID); + const privateIsArchivedMap = usePrivateIsArchivedMap(); + + return isApproverOfOutstandingPolicyReports(currentUserPersonalDetails.accountID, outstandingReportsByPolicyID?.[policyID ?? CONST.DEFAULT_NUMBER_ID], privateIsArchivedMap); +} + +export default useIsApproverOfOutstandingPolicyReports; diff --git a/src/libs/WorkspacesSettingsUtils.ts b/src/libs/WorkspacesSettingsUtils.ts index 3e45632dedf2..1251494f5065 100644 --- a/src/libs/WorkspacesSettingsUtils.ts +++ b/src/libs/WorkspacesSettingsUtils.ts @@ -140,7 +140,13 @@ function getOwnershipChecksDisplayText( return {title, text, buttonText}; } -function getLeaveWorkspaceConfirmationPrompt(policy: OnyxEntry, userEmail: string, ownerDisplayName: string, translate: LocaleContextProps['translate']): string { +function getLeaveWorkspaceConfirmationPrompt( + policy: OnyxEntry, + userEmail: string, + ownerDisplayName: string, + translate: LocaleContextProps['translate'], + isApproverOfOutstandingReports = false, +): string { const exporters = getConnectionExporters(policy); if (policy?.achAccount?.reimburser === userEmail) { @@ -155,7 +161,7 @@ function getLeaveWorkspaceConfirmationPrompt(policy: OnyxEntry, userEmai return translate('common.leaveWorkspaceConfirmationExporter', ownerDisplayName); } - if (isPolicyApprover(policy, userEmail)) { + if (isPolicyApprover(policy, userEmail) || isApproverOfOutstandingReports) { return translate('common.leaveWorkspaceConfirmationApprover', ownerDisplayName); } diff --git a/src/pages/workspace/WorkspaceOverviewPage.tsx b/src/pages/workspace/WorkspaceOverviewPage.tsx index f46b7a07d501..25fb8d60f250 100644 --- a/src/pages/workspace/WorkspaceOverviewPage.tsx +++ b/src/pages/workspace/WorkspaceOverviewPage.tsx @@ -21,6 +21,7 @@ import useConfirmModal from '@hooks/useConfirmModal'; import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDefaultFundID from '@hooks/useDefaultFundID'; +import useIsApproverOfOutstandingPolicyReports from '@hooks/useIsApproverOfOutstandingPolicyReports'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -183,6 +184,7 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa const {showLockedAccountModal} = useLockedAccountActions(); const [pendingRulesDocumentFile, setPendingRulesDocumentFile] = useState(); const [session] = useOnyx(ONYXKEYS.SESSION); + const isApproverOfOutstandingReports = useIsApproverOfOutstandingPolicyReports(policyID); const rulesDocumentSourceURL = useMemo( () => getRulesDocumentSourceURL(policy?.rulesDocumentURL, policyID, session?.encryptedAuthToken ?? ''), @@ -313,7 +315,7 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa const handleLeave = () => { const userEmail = session?.email ?? ''; const ownerDisplayName = personalDetails?.[policy?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID]?.displayName ?? ''; - const prompt = getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate); + const prompt = getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate, isApproverOfOutstandingReports); const isReimburser = policy?.achAccount?.reimburser === userEmail; if (isReimburser) { diff --git a/tests/unit/WorkspacesSettingsUtilsTest.ts b/tests/unit/WorkspacesSettingsUtilsTest.ts index a4cd59c681d2..d25fa472ddd9 100644 --- a/tests/unit/WorkspacesSettingsUtilsTest.ts +++ b/tests/unit/WorkspacesSettingsUtilsTest.ts @@ -266,6 +266,11 @@ describe('WorkspacesSettingsUtils', () => { expect(getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate)).toBe('common.leaveWorkspaceConfirmationApprover'); }); + it('returns approver key when user approves outstanding reports without being in the approval workflow', () => { + const policy = createMock({role: CONST.POLICY.ROLE.ADMIN}); + expect(getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate, true)).toBe('common.leaveWorkspaceConfirmationApprover'); + }); + it('returns admin key when the policy role is admin', () => { const policy = createMock({role: CONST.POLICY.ROLE.ADMIN}); expect(getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate)).toBe('common.leaveWorkspaceConfirmationAdmin');