Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);

Expand All @@ -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'),
Expand Down
23 changes: 23 additions & 0 deletions src/hooks/useIsApproverOfOutstandingPolicyReports.ts
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 8 additions & 2 deletions src/libs/WorkspacesSettingsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ function getOwnershipChecksDisplayText(
return {title, text, buttonText};
}

function getLeaveWorkspaceConfirmationPrompt(policy: OnyxEntry<Policy>, userEmail: string, ownerDisplayName: string, translate: LocaleContextProps['translate']): string {
function getLeaveWorkspaceConfirmationPrompt(
policy: OnyxEntry<Policy>,
userEmail: string,
ownerDisplayName: string,
translate: LocaleContextProps['translate'],
isApproverOfOutstandingReports = false,
): string {
const exporters = getConnectionExporters(policy);

if (policy?.achAccount?.reimburser === userEmail) {
Expand All @@ -155,7 +161,7 @@ function getLeaveWorkspaceConfirmationPrompt(policy: OnyxEntry<Policy>, userEmai
return translate('common.leaveWorkspaceConfirmationExporter', ownerDisplayName);
}

if (isPolicyApprover(policy, userEmail)) {
if (isPolicyApprover(policy, userEmail) || isApproverOfOutstandingReports) {
return translate('common.leaveWorkspaceConfirmationApprover', ownerDisplayName);
}

Expand Down
4 changes: 3 additions & 1 deletion src/pages/workspace/WorkspaceOverviewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -183,6 +184,7 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa
const {showLockedAccountModal} = useLockedAccountActions();
const [pendingRulesDocumentFile, setPendingRulesDocumentFile] = useState<FileObject | undefined>();
const [session] = useOnyx(ONYXKEYS.SESSION);
const isApproverOfOutstandingReports = useIsApproverOfOutstandingPolicyReports(policyID);

const rulesDocumentSourceURL = useMemo(
() => getRulesDocumentSourceURL(policy?.rulesDocumentURL, policyID, session?.encryptedAuthToken ?? ''),
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions tests/unit/WorkspacesSettingsUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Policy>({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<Policy>({role: CONST.POLICY.ROLE.ADMIN});
expect(getLeaveWorkspaceConfirmationPrompt(policy, userEmail, ownerDisplayName, translate)).toBe('common.leaveWorkspaceConfirmationAdmin');
Expand Down
Loading