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
39 changes: 0 additions & 39 deletions src/components/DelegateNoAccessModal.tsx

This file was deleted.

74 changes: 74 additions & 0 deletions src/components/DelegateNoAccessModalProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, {createContext, useMemo, useState} from 'react';
import type {PropsWithChildren} from 'react';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import AccountUtils from '@libs/AccountUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ConfirmModal from './ConfirmModal';
import Text from './Text';
import TextLink from './TextLink';

type DelegateNoAccessContextType = {
/** Whether the current user is acting as delegate */
isActingAsDelegate: boolean;

/** Whether the current user has restricted access as a submitter only delegate */
isDelegateAccessRestricted: boolean;

/** Function to show the delegate no access modal */
showDelegateNoAccessModal: () => void;
};

const DelegateNoAccessContext = createContext<DelegateNoAccessContextType>({
isActingAsDelegate: false,
isDelegateAccessRestricted: false,
showDelegateNoAccessModal: () => {},
});

function DelegateNoAccessModalProvider({children}: PropsWithChildren) {
const {translate} = useLocalize();
const [isModalOpen, setIsModalOpen] = useState(false);
const currentUserDetails = useCurrentUserPersonalDetails();
const delegatorEmail = currentUserDetails?.login ?? '';
const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true});
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const isDelegateAccessRestricted = isActingAsDelegate && AccountUtils.isDelegateOnlySubmitter(account);

const delegateNoAccessPrompt = (
<Text>
{translate('delegate.notAllowedMessageStart')}
<TextLink href={CONST.DELEGATE_ROLE_HELP_DOT_ARTICLE_LINK}>{translate('delegate.notAllowedMessageHyperLinked')}</TextLink>
{translate('delegate.notAllowedMessageEnd', {accountOwnerEmail: delegatorEmail})}
</Text>
);
const contextValue = useMemo(
() => ({
isActingAsDelegate,
isDelegateAccessRestricted,
showDelegateNoAccessModal: () => setIsModalOpen(true),
}),
[isActingAsDelegate, isDelegateAccessRestricted],
);

return (
<DelegateNoAccessContext.Provider value={contextValue}>
{children}
<ConfirmModal
isVisible={isModalOpen}
onConfirm={() => setIsModalOpen(false)}
onCancel={() => setIsModalOpen(false)}
title={translate('delegate.notAllowed')}
prompt={delegateNoAccessPrompt}
confirmText={translate('common.buttonConfirm')}
shouldShowCancelButton={false}
/>
</DelegateNoAccessContext.Provider>
);
}

DelegateNoAccessModalProvider.displayName = 'DelegateNoAccessModalProvider';

export default DelegateNoAccessModalProvider;
export {DelegateNoAccessContext};
20 changes: 7 additions & 13 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useRoute} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react';
import {ActivityIndicator, InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -79,7 +79,6 @@ import {
} from '@userActions/IOU';
import {markAsCash as markAsCashAction} from '@userActions/Transaction';
import CONST from '@src/CONST';
import useDelegateUserDetails from '@src/hooks/useDelegateUserDetails';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
Expand All @@ -94,7 +93,7 @@ import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
import type {DropdownOption} from './ButtonWithDropdownMenu/types';
import ConfirmModal from './ConfirmModal';
import DecisionModal from './DecisionModal';
import DelegateNoAccessModal from './DelegateNoAccessModal';
import {DelegateNoAccessContext} from './DelegateNoAccessModalProvider';
import Header from './Header';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
Expand Down Expand Up @@ -295,8 +294,7 @@ function MoneyReportHeader({
const bankAccountRoute = getBankAccountRoute(chatReport);
const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(moneyRequestReport, shouldShowPayButton);
const isAnyTransactionOnHold = hasHeldExpensesReportUtils(moneyRequestReport?.reportID);
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const {isDelegateAccessRestricted, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext);
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {canBeMissing: true});

const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP;
Expand All @@ -310,7 +308,7 @@ function MoneyReportHeader({
setPaymentType(type);
setRequestType(CONST.IOU.REPORT_ACTION_TYPE.PAY);
if (isDelegateAccessRestricted) {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
} else if (isAnyTransactionOnHold) {
InteractionManager.runAfterInteractions(() => setIsHoldMenuVisible(true));
} else if (isInvoiceReport) {
Expand All @@ -321,13 +319,13 @@ function MoneyReportHeader({
payMoneyRequest(type, chatReport, moneyRequestReport, true);
}
},
[chatReport, isAnyTransactionOnHold, isDelegateAccessRestricted, isInvoiceReport, moneyRequestReport, startAnimation],
[chatReport, isAnyTransactionOnHold, isDelegateAccessRestricted, showDelegateNoAccessModal, isInvoiceReport, moneyRequestReport, startAnimation],
);

const confirmApproval = () => {
setRequestType(CONST.IOU.REPORT_ACTION_TYPE.APPROVE);
if (isDelegateAccessRestricted) {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
} else if (isAnyTransactionOnHold) {
setIsHoldMenuVisible(true);
} else {
Expand Down Expand Up @@ -705,7 +703,7 @@ function MoneyReportHeader({
value: CONST.REPORT.SECONDARY_ACTIONS.UNAPPROVE,
onSelected: () => {
if (isDelegateAccessRestricted) {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
return;
}

Expand Down Expand Up @@ -1020,10 +1018,6 @@ function MoneyReportHeader({
transactionCount={transactionIDs?.length ?? 0}
/>
)}
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
<DecisionModal
title={translate('common.downloadFailedTitle')}
prompt={translate('common.downloadFailedDescription')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {ActivityIndicator, FlatList, View} from 'react-native';
import type {LayoutChangeEvent, ListRenderItemInfo, ViewToken} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withDelay, withSpring, withTiming} from 'react-native-reanimated';
import type {LayoutRectangle} from 'react-native/Libraries/Types/CoreEventTypes';
import Button from '@components/Button';
import {getButtonRole} from '@components/Button/utils';
import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
import DelegateNoAccessModal from '@components/DelegateNoAccessModal';
import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import ImageSVG from '@components/ImageSVG';
Expand Down Expand Up @@ -105,7 +105,6 @@ function MoneyRequestReportPreviewContent({
policy,
invoiceReceiverPersonalDetail,
lastTransactionViolations,
isDelegateAccessRestricted,
renderTransactionItem,
onCarouselLayout,
onWrapperLayout,
Expand Down Expand Up @@ -190,7 +189,7 @@ function MoneyRequestReportPreviewContent({

// The submit button should be success green color only if the user is submitter and the policy does not have Scheduled Submit turned on
const isWaitingForSubmissionFromCurrentUser = useMemo(() => isWaitingForSubmissionFromCurrentUserReportUtils(chatReport, policy), [chatReport, policy]);
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const {isDelegateAccessRestricted, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext);
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, {canBeMissing: true});
const confirmPayment = useCallback(
(type: PaymentMethodType | undefined, payAsBusiness?: boolean) => {
Expand All @@ -200,7 +199,7 @@ function MoneyRequestReportPreviewContent({
setPaymentType(type);
setRequestType(CONST.IOU.REPORT_ACTION_TYPE.PAY);
if (isDelegateAccessRestricted) {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
} else if (hasHeldExpensesReportUtils(iouReport?.reportID)) {
setIsHoldMenuVisible(true);
} else if (chatReport && iouReport) {
Expand All @@ -212,13 +211,13 @@ function MoneyRequestReportPreviewContent({
}
}
},
[chatReport, iouReport, isDelegateAccessRestricted, startAnimation],
[chatReport, iouReport, isDelegateAccessRestricted, showDelegateNoAccessModal, startAnimation],
);

const confirmApproval = () => {
setRequestType(CONST.IOU.REPORT_ACTION_TYPE.APPROVE);
if (isDelegateAccessRestricted) {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
} else if (hasHeldExpensesReportUtils(iouReport?.reportID)) {
setIsHoldMenuVisible(true);
} else {
Expand Down Expand Up @@ -767,10 +766,6 @@ function MoneyRequestReportPreviewContent({
</View>
</PressableWithoutFeedback>
</View>
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
{isHoldMenuVisible && !!iouReport && !!requestType && (
<ProcessMoneyReportHoldMenu
nonHeldAmount={!hasOnlyHeldExpenses && hasValidNonHeldAmount ? nonHeldAmount : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, {useCallback, useMemo, useState} from 'react';
import type {LayoutChangeEvent, ListRenderItem} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import TransactionPreview from '@components/ReportActionItem/TransactionPreview';
import useDelegateUserDetails from '@hooks/useDelegateUserDetails';
import usePolicy from '@hooks/usePolicy';
import useReportWithTransactionsAndViolations from '@hooks/useReportWithTransactionsAndViolations';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
Expand Down Expand Up @@ -54,7 +53,6 @@ function MoneyRequestReportPreview({
const policy = usePolicy(policyID);
const lastTransaction = transactions?.at(0);
const lastTransactionViolations = useTransactionViolations(lastTransaction?.transactionID);
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const isTrackExpenseAction = isTrackExpenseActionReportActionsUtils(action);
const isSplitBillAction = isSplitBillActionReportActionsUtils(action);
const [currentWidth, setCurrentWidth] = useState<number>(0);
Expand Down Expand Up @@ -125,7 +123,6 @@ function MoneyRequestReportPreview({
invoiceReceiverPersonalDetail={invoiceReceiverPersonalDetail}
invoiceReceiverPolicy={invoiceReceiverPolicy}
lastTransactionViolations={lastTransactionViolations}
isDelegateAccessRestricted={isDelegateAccessRestricted}
renderTransactionItem={renderItem}
onCarouselLayout={(e: LayoutChangeEvent) => {
setCurrentWidth(e.nativeEvent.layout.width);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ type MoneyRequestReportPreviewContentOnyxProps = {
policy: OnyxEntry<Policy>;
invoiceReceiverPersonalDetail: OnyxEntry<PersonalDetails>;
lastTransactionViolations: TransactionViolations;
isDelegateAccessRestricted: boolean;
};

type MoneyRequestReportPreviewContentProps = MoneyRequestReportPreviewContentOnyxProps &
Expand Down
18 changes: 0 additions & 18 deletions src/hooks/useDelegateUserDetails.ts

This file was deleted.

3 changes: 2 additions & 1 deletion src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {useOnyx, withOnyx} from 'react-native-onyx';
import ComposeProviders from '@components/ComposeProviders';
import DelegateNoAccessModalProvider from '@components/DelegateNoAccessModalProvider';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import LockedAccountModalProvider from '@components/LockedAccountModalProvider';
import OptionsListContextProvider from '@components/OptionListContextProvider';
Expand Down Expand Up @@ -539,7 +540,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
}

return (
<ComposeProviders components={[OptionsListContextProvider, SidebarOrderedReportsContextProvider, SearchContextProvider, LockedAccountModalProvider]}>
<ComposeProviders components={[OptionsListContextProvider, SidebarOrderedReportsContextProvider, SearchContextProvider, LockedAccountModalProvider, DelegateNoAccessModalProvider]}>
<RootStack.Navigator persistentScreens={[NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, SCREENS.SEARCH.ROOT]}>
{/* This has to be the first navigator in auth screens. */}
<RootStack.Screen
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {useIsFocused} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useCallback, useContext, useEffect, useMemo} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import AttachmentPicker from '@components/AttachmentPicker';
import {DelegateNoAccessContext} from '@components/DelegateNoAccessModalProvider';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import type {PopoverMenuItem} from '@components/PopoverMenu';
Expand All @@ -27,10 +28,8 @@ import {startMoneyRequest} from '@userActions/IOU';
import {close} from '@userActions/Modal';
import {createNewReport, setIsComposerFullSize} from '@userActions/Report';
import {clearOutTaskInfoAndNavigate} from '@userActions/Task';
import DelegateNoAccessModal from '@src/components/DelegateNoAccessModal';
import type {IOUType} from '@src/CONST';
import CONST from '@src/CONST';
import useDelegateUserDetails from '@src/hooks/useDelegateUserDetails';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
Expand Down Expand Up @@ -129,8 +128,7 @@ function AttachmentPickerWithMenuItems({
const {translate} = useLocalize();
const {windowHeight, windowWidth} = useWindowDimensions();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const {isDelegateAccessRestricted, showDelegateNoAccessModal} = useContext(DelegateNoAccessContext);
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true});
const {isProduction} = useEnvironment();

Expand Down Expand Up @@ -173,7 +171,7 @@ function AttachmentPickerWithMenuItems({
onSelected: () => {
if (isDelegateAccessRestricted) {
close(() => {
setIsNoDelegateAccessMenuVisible(true);
showDelegateNoAccessModal();
});
return;
}
Expand All @@ -199,7 +197,7 @@ function AttachmentPickerWithMenuItems({
}));

return moneyRequestOptionsList.filter((item, index, self) => index === self.findIndex((t) => t.text === item.text));
}, [translate, shouldUseNarrowLayout, report, policy, reportParticipantIDs, selectOption, isDelegateAccessRestricted]);
}, [translate, shouldUseNarrowLayout, report, policy, reportParticipantIDs, selectOption, isDelegateAccessRestricted, showDelegateNoAccessModal]);

const createReportOption: PopoverMenuItem[] = useMemo(() => {
if (!isPolicyExpenseChat(report) || !isPaidGroupPolicy(report) || !isReportOwner(report)) {
Expand Down Expand Up @@ -414,10 +412,6 @@ function AttachmentPickerWithMenuItems({
withoutOverlay
anchorRef={actionButtonRef}
/>
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
</>
);
}}
Expand Down
Loading
Loading