From a047d8a5bf0ec13aef46af8998f2821133963ca4 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 6 Nov 2024 17:08:00 +0530 Subject: [PATCH 01/31] show DelegateNoAccessModal for restricted delegate actions --- src/CONST.ts | 6 ++ src/components/AddressForm.tsx | 6 +- src/components/DelegateNoAccessModal.tsx | 8 +-- src/components/DelegateNoAccessWrapper.tsx | 71 +++++++++++++++++++ src/components/Form/FormProvider.tsx | 2 +- src/pages/AddressPage.tsx | 21 +++++- src/pages/settings/InitialSettingsPage.tsx | 13 ++++ .../Profile/Contacts/ContactMethodsPage.tsx | 2 - .../Profile/Contacts/NewContactMethodPage.tsx | 7 +- .../PersonalDetails/DateOfBirthPage.tsx | 21 ++++-- .../Profile/PersonalDetails/LegalNamePage.tsx | 25 +++++-- .../PersonalDetails/PhoneNumberPage.tsx | 21 +++++- .../Security/SecuritySettingsPage.tsx | 18 ++++- .../settings/Wallet/WalletPage/WalletPage.tsx | 19 +++++ 14 files changed, 212 insertions(+), 28 deletions(-) create mode 100644 src/components/DelegateNoAccessWrapper.tsx diff --git a/src/CONST.ts b/src/CONST.ts index 8a1e9cfbf67c..5c5745f7cfe6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4500,6 +4500,12 @@ const CONST = { ALL: 'all', SUBMITTER: 'submitter', }, + DELEGATE: { + DENIED_ACCESS_VARIANTS: { + DELEGATE: 'delegate', + SUBMITTER: 'submitter', + }, + }, DELEGATE_ROLE_HELPDOT_ARTICLE_LINK: 'https://help.expensify.com/expensify-classic/hubs/copilots-and-delegates/', STRIPE_GBP_AUTH_STATUSES: { SUCCEEDED: 'succeeded', diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 4470481d2be6..709770617fdc 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -56,6 +56,9 @@ type AddressFormProps = { /** A unique Onyx key identifying the form */ formID: typeof ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM | typeof ONYXKEYS.FORMS.HOME_ADDRESS_FORM; + + /** Whether or not validation should be skipped */ + skipValidation?: boolean; }; function AddressForm({ @@ -70,6 +73,7 @@ function AddressForm({ street2 = '', submitButtonText = '', zip = '', + skipValidation = false, }: AddressFormProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -139,7 +143,7 @@ function AddressForm({ void; - delegatorEmail: string; }; -export default function DelegateNoAccessModal({isNoDelegateAccessMenuVisible = false, onClose, delegatorEmail = ''}: DelegateNoAccessModalProps) { +export default function DelegateNoAccessModal({isNoDelegateAccessMenuVisible = false, onClose}: DelegateNoAccessModalProps) { const {translate} = useLocalize(); - const noDelegateAccessPromptStart = translate('delegate.notAllowedMessageStart', {accountOwnerEmail: delegatorEmail}); + const {delegatorEmail} = useDelegateUserDetails(); + const noDelegateAccessPromptStart = translate('delegate.notAllowedMessageStart', {accountOwnerEmail: delegatorEmail ?? ''}); const noDelegateAccessHyperLinked = translate('delegate.notAllowedMessageHyperLinked'); - const delegateNoAccessPrompt = ( {noDelegateAccessPromptStart} diff --git a/src/components/DelegateNoAccessWrapper.tsx b/src/components/DelegateNoAccessWrapper.tsx new file mode 100644 index 000000000000..36e675547d7e --- /dev/null +++ b/src/components/DelegateNoAccessWrapper.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import {OnyxEntry, useOnyx} from 'react-native-onyx'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import AccountUtils from '@libs/AccountUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import {Account} from '@src/types/onyx'; +import callOrReturn from '@src/types/utils/callOrReturn'; +import {FullPageNotFoundViewProps} from './BlockingViews/FullPageNotFoundView'; + +const DENIED_ACCESS_VARIANTS = { + [CONST.DELEGATE.DENIED_ACCESS_VARIANTS.DELEGATE]: (account: OnyxEntry) => isDelegate(account), + [CONST.DELEGATE.DENIED_ACCESS_VARIANTS.SUBMITTER]: (account: OnyxEntry) => isSubmitter(account), +} as const satisfies Record) => boolean>; + +type AccessDeniedVariants = keyof typeof DENIED_ACCESS_VARIANTS; + +type DelegateNoAccessWrapperProps = { + accessDeniedVariants?: AccessDeniedVariants[]; + FullPageNotFoundViewProps?: FullPageNotFoundViewProps; + shouldShowFullScreenFallback?: boolean; + children: (() => React.ReactNode) | React.ReactNode; +}; + +type PageNotFoundFallbackProps = { + shouldShowFullScreenFallback?: boolean; +}; + +function isDelegate(account: OnyxEntry) { + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + return isActingAsDelegate; +} + +function isSubmitter(account: OnyxEntry) { + const isDelegateOnlySubmitter = AccountUtils.isDelegateOnlySubmitter(account); + return isDelegateOnlySubmitter; +} + +function PageNotFoundFallback({shouldShowFullScreenFallback}: PageNotFoundFallbackProps) { + const {shouldUseNarrowLayout} = useResponsiveLayout(); + return ( + { + if (shouldShowFullScreenFallback) { + Navigation.dismissModal(); + return; + } + Navigation.goBack(); + }} + shouldShowBackButton={!shouldShowFullScreenFallback ? shouldUseNarrowLayout : undefined} + /> + ); +} + +function DelegateNoAccessWrapper({accessDeniedVariants = [], shouldShowFullScreenFallback, ...props}: DelegateNoAccessWrapperProps) { + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isPageAccessDenied = accessDeniedVariants.reduce((acc, variant) => { + const accessDeniedFunction = DENIED_ACCESS_VARIANTS[variant]; + return acc || accessDeniedFunction(account); + }, false); + if (isPageAccessDenied) { + return ; + } + return callOrReturn(props.children); +} + +export default DelegateNoAccessWrapper; diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx index 1d66953c1070..d1b45e1d9327 100644 --- a/src/components/Form/FormProvider.tsx +++ b/src/components/Form/FormProvider.tsx @@ -44,7 +44,7 @@ type FormProviderProps = FormProps}) => ReactNode) | ReactNode; /** Callback to validate the form */ - validate?: (values: FormOnyxValues) => FormInputErrors; + validate?: (values: FormOnyxValues) => FormInputErrors | undefined; /** Should validate function be called when input loose focus */ shouldValidateOnBlur?: boolean; diff --git a/src/pages/AddressPage.tsx b/src/pages/AddressPage.tsx index 88e52409751b..670b582e08a2 100644 --- a/src/pages/AddressPage.tsx +++ b/src/pages/AddressPage.tsx @@ -1,6 +1,7 @@ import React, {useCallback, useEffect, useState} from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; +import {type OnyxEntry, useOnyx} from 'react-native-onyx'; import AddressForm from '@components/AddressForm'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -37,6 +38,17 @@ function AddressPage({title, address, updateAddress, isLoadingApp = true, backTo const [city, setCity] = useState(address?.city); const [zipcode, setZipcode] = useState(address?.zip); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + + // For delegates, modifying legal address is a restricted action. + // So, on pressing submit, skip validation and show delegateNoAccessModal + const skipValidation = isActingAsDelegate; + const handleSubmit = (values: FormOnyxValues) => { + isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateAddress(values); + }; + useEffect(() => { if (!address) { return; @@ -91,7 +103,7 @@ function AddressPage({title, address, updateAddress, isLoadingApp = true, backTo ) : ( )} + setIsNoDelegateAccessMenuVisible(false)} + /> ); } diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 8c1d68e0a95b..3256a6dbc500 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -8,6 +8,7 @@ import type {ValueOf} from 'type-fest'; import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; import ConfirmModal from '@components/ConfirmModal'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {InitialURLContext} from '@components/InitialURLContextProvider'; @@ -83,6 +84,10 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + const network = useNetwork(); const theme = useTheme(); const styles = useThemeStyles(); @@ -242,6 +247,10 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr } : { action() { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } resetExitSurveyForm(() => Navigation.navigate(ROUTES.SETTINGS_EXIT_SURVEY_REASON)); }, }), @@ -435,6 +444,10 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr onCancel={() => toggleSignoutConfirmModal(false)} /> + setIsNoDelegateAccessMenuVisible(false)} + /> ); } diff --git a/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx index 92a246949c53..dac36a15cefd 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx @@ -36,7 +36,6 @@ function ContactMethodsPage({route}: ContactMethodsPageProps) { const [account] = useOnyx(ONYXKEYS.ACCOUNT); const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); - const {delegatorEmail} = useDelegateUserDetails(); // Sort the login names by placing the one corresponding to the default contact method as the first item before displaying the contact methods. // The default contact method is determined by checking against the session email (the current login). @@ -132,7 +131,6 @@ function ContactMethodsPage({route}: ContactMethodsPageProps) { setIsNoDelegateAccessMenuVisible(false)} - delegatorEmail={delegatorEmail ?? ''} /> ); diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index c2a7e1b6712c..d23af0371ef3 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -3,6 +3,7 @@ import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper'; import DotIndicatorMessage from '@components/DotIndicatorMessage'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -110,7 +111,8 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) { }, [navigateBackTo]); return ( - + // + loginInputRef.current?.focus()} includeSafeAreaPaddingBottom={false} @@ -174,7 +176,8 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) { description={translate('contacts.enterMagicCode', {contactMethod})} /> - + + // ); } diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx index e91093731c03..882f29d51b99 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx @@ -1,8 +1,9 @@ import {subYears} from 'date-fns'; -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; @@ -16,7 +17,7 @@ import * as ValidationUtils from '@libs/ValidationUtils'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import INPUT_IDS from '@src/types/form/DateOfBirthForm'; +import INPUT_IDS, {DateOfBirthForm} from '@src/types/form/DateOfBirthForm'; import type {PrivatePersonalDetails} from '@src/types/onyx'; type DateOfBirthPageOnyxProps = { @@ -30,6 +31,9 @@ type DateOfBirthPageProps = DateOfBirthPageOnyxProps; function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBirthPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); /** * @returns An object containing the errors for each inputID @@ -48,6 +52,13 @@ function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBi return errors; }, []); + // For delegates, modifying legal DOB is a restricted action. + // So, on pressing submit, skip validation and show delegateNoAccessModal + + const skipValidation = isActingAsDelegate; + const handleSubmit = (DOB: DateOfBirthForm) => { + isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : PersonalDetails.updateDateOfBirth(DOB); + }; return ( diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx index 99e9c910cbdf..cf9a8ec398a3 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx @@ -1,7 +1,8 @@ -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; @@ -33,12 +34,14 @@ type LegalNamePageProps = LegalNamePageOnyxProps; const updateLegalName = (values: PrivatePersonalDetails) => { PersonalDetails.updateLegalName(values.legalFirstName?.trim() ?? '', values.legalLastName?.trim() ?? ''); }; - function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNamePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const legalFirstName = privatePersonalDetails?.legalFirstName ?? ''; const legalLastName = privatePersonalDetails?.legalLastName ?? ''; + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const validate = useCallback( (values: FormOnyxValues) => { @@ -83,6 +86,14 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP [translate], ); + // For delegates, modifying legal Name is a restricted action. + // So, on pressing submit, skip validation and show delegateNoAccessModal + + const skipValidation = isActingAsDelegate; + const handleSubmit = (values: PrivatePersonalDetails) => { + isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateLegalName(values); + }; + return ( @@ -130,6 +141,10 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP )} + setIsNoDelegateAccessMenuVisible(false)} + /> ); } diff --git a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx index 12c6f011c6a2..536fa510ef54 100644 --- a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx @@ -1,6 +1,7 @@ import {Str} from 'expensify-common'; -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; import {useOnyx} from 'react-native-onyx'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; @@ -32,6 +33,10 @@ function PhoneNumberPage() { const validateLoginError = ErrorUtils.getEarliestErrorField(privatePersonalDetails, 'phoneNumber'); const currenPhoneNumber = privatePersonalDetails?.phoneNumber ?? ''; + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + const updatePhoneNumber = (values: PrivatePersonalDetails) => { // Clear the error when the user tries to submit the form if (validateLoginError) { @@ -66,6 +71,12 @@ function PhoneNumberPage() { }, [translate, validateLoginError], ); + // For delegates, modifying Phone Number is a restricted action. + // So, on pressing submit, skip validation and show delegateNoAccessModal + const skipValidation = isActingAsDelegate; + const handleSubmit = (values: PrivatePersonalDetails) => { + isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updatePhoneNumber(values); + }; return ( @@ -112,6 +123,10 @@ function PhoneNumberPage() { )} + setIsNoDelegateAccessMenuVisible(false)} + /> ); } diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index cd8e7c14d882..f646725319b3 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -5,6 +5,7 @@ import {Dimensions, View} from 'react-native'; import type {GestureResponderEvent} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import {FallbackAvatar} from '@components/Icon/Expensicons'; @@ -20,6 +21,7 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -63,6 +65,10 @@ function SecuritySettingsPage() { anchorPositionRight: 0, }); + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + + // const [account] = useOnyx(ONYXKEYS.ACCOUNT); + // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const setMenuPosition = useCallback(() => { if (!delegateButtonRef.current) { return; @@ -92,7 +98,9 @@ function SecuritySettingsPage() { setShouldShowDelegatePopoverMenu(true); setSelectedDelegate(delegate); }; - + const showDelegateNoAccessMenu = () => { + setIsNoDelegateAccessMenuVisible(true); + }; useLayoutEffect(() => { const popoverPositionListener = Dimensions.addEventListener('change', () => { debounce(setMenuPosition, CONST.TIMING.RESIZE_DEBOUNCE_TIME)(); @@ -111,12 +119,12 @@ function SecuritySettingsPage() { { translationKey: 'twoFactorAuth.headerTitle', icon: Expensicons.Shield, - action: waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_2FA.getRoute())), + action: isActingAsDelegate ? showDelegateNoAccessMenu : waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_2FA.getRoute())), }, { translationKey: 'closeAccountPage.closeAccount', icon: Expensicons.ClosedSign, - action: waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_CLOSE)), + action: isActingAsDelegate ? showDelegateNoAccessMenu : waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_CLOSE)), }, ]; @@ -333,6 +341,10 @@ function SecuritySettingsPage() { /> + setIsNoDelegateAccessMenuVisible(false)} + /> )} diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 7b9366370349..79b0a434a5ad 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -7,6 +7,7 @@ import {ActivityIndicator, Dimensions, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; import ConfirmModal from '@components/ConfirmModal'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -22,6 +23,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; +import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePaymentMethodState from '@hooks/usePaymentMethodState'; @@ -59,6 +61,10 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS, {initialValue: {}}); const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated}); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -179,6 +185,10 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { setMenuPosition(); return; } + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } setShouldShowAddPaymentMenu(true); setMenuPosition(); }; @@ -499,6 +509,11 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { } onPress={() => { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + if (!isUserValidated) { Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_ENABLE_PAYMENTS)); return; @@ -595,6 +610,10 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { anchorRef={addPaymentMethodAnchorRef} shouldShowPersonalBankAccountOption /> + setIsNoDelegateAccessMenuVisible(false)} + /> ); } From f33b43f4824944504a9e3c5823e6a7b9efc4890e Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:22:11 +0530 Subject: [PATCH 02/31] LegalNamePage --- .../settings/Profile/PersonalDetails/LegalNamePage.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx index cf9a8ec398a3..4b30160f88e2 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx @@ -39,8 +39,7 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP const {translate} = useLocalize(); const legalFirstName = privatePersonalDetails?.legalFirstName ?? ''; const legalLastName = privatePersonalDetails?.legalLastName ?? ''; - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const validate = useCallback( @@ -88,10 +87,13 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP // For delegates, modifying legal Name is a restricted action. // So, on pressing submit, skip validation and show delegateNoAccessModal - const skipValidation = isActingAsDelegate; const handleSubmit = (values: PrivatePersonalDetails) => { - isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateLegalName(values); + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + updateLegalName(values); }; return ( From cd5a45311afca70c4b6bd547a992ed393d676c62 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:26:06 +0530 Subject: [PATCH 03/31] DOB --- .../PersonalDetails/DateOfBirthPage.tsx | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx index 882f29d51b99..76f67e6dad36 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx @@ -17,7 +17,7 @@ import * as ValidationUtils from '@libs/ValidationUtils'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import INPUT_IDS, {DateOfBirthForm} from '@src/types/form/DateOfBirthForm'; +import INPUT_IDS, {type DateOfBirthForm} from '@src/types/form/DateOfBirthForm'; import type {PrivatePersonalDetails} from '@src/types/onyx'; type DateOfBirthPageOnyxProps = { @@ -31,8 +31,10 @@ type DateOfBirthPageProps = DateOfBirthPageOnyxProps; function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBirthPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + // const [account] = useOnyx(ONYXKEYS.ACCOUNT); + // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); /** @@ -52,12 +54,16 @@ function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBi return errors; }, []); + // For delegates, modifying legal DOB is a restricted action. // So, on pressing submit, skip validation and show delegateNoAccessModal - const skipValidation = isActingAsDelegate; const handleSubmit = (DOB: DateOfBirthForm) => { - isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : PersonalDetails.updateDateOfBirth(DOB); + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + PersonalDetails.updateDateOfBirth(DOB); }; return ( @@ -90,6 +96,10 @@ function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBi /> )} + setIsNoDelegateAccessMenuVisible(false)} + /> ); } From 61b69c188f579f9e6f2396fab0f5f4e8f36d9811 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:26:52 +0530 Subject: [PATCH 04/31] PhoneNumber --- .../Profile/PersonalDetails/PhoneNumberPage.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx index 536fa510ef54..f4eed49c8a2e 100644 --- a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx @@ -33,8 +33,9 @@ function PhoneNumberPage() { const validateLoginError = ErrorUtils.getEarliestErrorField(privatePersonalDetails, 'phoneNumber'); const currenPhoneNumber = privatePersonalDetails?.phoneNumber ?? ''; - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + // const [account] = useOnyx(ONYXKEYS.ACCOUNT); + // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const updatePhoneNumber = (values: PrivatePersonalDetails) => { @@ -75,7 +76,11 @@ function PhoneNumberPage() { // So, on pressing submit, skip validation and show delegateNoAccessModal const skipValidation = isActingAsDelegate; const handleSubmit = (values: PrivatePersonalDetails) => { - isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updatePhoneNumber(values); + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + updatePhoneNumber(values); }; return ( From feff84b83e9d103ba52e8c62b67664872766e3c8 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:27:22 +0530 Subject: [PATCH 05/31] Address --- src/pages/AddressPage.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pages/AddressPage.tsx b/src/pages/AddressPage.tsx index 670b582e08a2..714f48a5e04a 100644 --- a/src/pages/AddressPage.tsx +++ b/src/pages/AddressPage.tsx @@ -1,5 +1,6 @@ import React, {useCallback, useEffect, useState} from 'react'; -import {type OnyxEntry, useOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import AddressForm from '@components/AddressForm'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -38,15 +39,21 @@ function AddressPage({title, address, updateAddress, isLoadingApp = true, backTo const [city, setCity] = useState(address?.city); const [zipcode, setZipcode] = useState(address?.zip); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + // const [account] = useOnyx(ONYXKEYS.ACCOUNT); + // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); // For delegates, modifying legal address is a restricted action. // So, on pressing submit, skip validation and show delegateNoAccessModal const skipValidation = isActingAsDelegate; const handleSubmit = (values: FormOnyxValues) => { - isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateAddress(values); + if (!!isActingAsDelegate) { + console.log('inside' + isActingAsDelegate); + setIsNoDelegateAccessMenuVisible(true); + return; + } + updateAddress(values); }; useEffect(() => { From 7cadc0fdaed45991debe675ce0775213aecffd88 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:28:49 +0530 Subject: [PATCH 06/31] Wallet --- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 79b0a434a5ad..35e3332bb0d6 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -23,7 +23,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; -import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePaymentMethodState from '@hooks/usePaymentMethodState'; @@ -61,8 +60,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS, {initialValue: {}}); const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated}); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const theme = useTheme(); From 285b06156223c48a21a03e8355084e0f88772310 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:35:46 +0530 Subject: [PATCH 07/31] cleanup --- src/pages/AddressPage.tsx | 2 -- src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx | 2 -- src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx | 1 + src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/AddressPage.tsx b/src/pages/AddressPage.tsx index 714f48a5e04a..d2ea2bd03530 100644 --- a/src/pages/AddressPage.tsx +++ b/src/pages/AddressPage.tsx @@ -39,8 +39,6 @@ function AddressPage({title, address, updateAddress, isLoadingApp = true, backTo const [city, setCity] = useState(address?.city); const [zipcode, setZipcode] = useState(address?.zip); - // const [account] = useOnyx(ONYXKEYS.ACCOUNT); - // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx index 76f67e6dad36..83c8ec37c5f9 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx @@ -31,8 +31,6 @@ type DateOfBirthPageProps = DateOfBirthPageOnyxProps; function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBirthPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - // const [account] = useOnyx(ONYXKEYS.ACCOUNT); - // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx index 4b30160f88e2..86ddd5a0a64e 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx @@ -87,6 +87,7 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP // For delegates, modifying legal Name is a restricted action. // So, on pressing submit, skip validation and show delegateNoAccessModal + const skipValidation = isActingAsDelegate; const handleSubmit = (values: PrivatePersonalDetails) => { if (isActingAsDelegate) { diff --git a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx index f4eed49c8a2e..b078dd7964dc 100644 --- a/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/PhoneNumberPage.tsx @@ -33,8 +33,6 @@ function PhoneNumberPage() { const validateLoginError = ErrorUtils.getEarliestErrorField(privatePersonalDetails, 'phoneNumber'); const currenPhoneNumber = privatePersonalDetails?.phoneNumber ?? ''; - // const [account] = useOnyx(ONYXKEYS.ACCOUNT); - // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); @@ -72,6 +70,7 @@ function PhoneNumberPage() { }, [translate, validateLoginError], ); + // For delegates, modifying Phone Number is a restricted action. // So, on pressing submit, skip validation and show delegateNoAccessModal const skipValidation = isActingAsDelegate; From 617282cd105721ad8b0b67818fa0bdca43d2cb30 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:36:50 +0530 Subject: [PATCH 08/31] Switch To OD --- src/pages/settings/InitialSettingsPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 3256a6dbc500..8da9bd8fd64e 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -84,8 +84,8 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const network = useNetwork(); @@ -279,7 +279,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr }, ], }; - }, [styles.pt4, signOut, setInitialURL]); + }, [styles.pt4, signOut, setInitialURL, isActingAsDelegate]); /** * Retuns JSX.Element with menu items From 7adfac1d27ab1bd8074160199f767116cd73e43f Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 16:46:53 +0530 Subject: [PATCH 09/31] Payment method menuItems --- .../settings/Wallet/WalletPage/WalletPage.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 35e3332bb0d6..66f7772eb184 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -505,6 +505,8 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { return ( } onPress={() => { if (isActingAsDelegate) { @@ -519,8 +521,6 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { Navigation.navigate(ROUTES.SETTINGS_ENABLE_PAYMENTS); }} disabled={network.isOffline} - title={translate('walletPage.enableWallet')} - icon={Expensicons.Wallet} wrapperStyle={[ styles.transferBalance, shouldUseNarrowLayout ? styles.mhn5 : styles.mhn8, @@ -565,6 +565,10 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { title={translate('walletPage.setDefaultConfirmation')} icon={Expensicons.Mail} onPress={() => { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } makeDefaultPaymentMethod(); setShouldShowDefaultDeleteMenu(false); }} @@ -574,7 +578,13 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { Modal.close(() => setShowConfirmDeleteModal(true))} + onPress={() => { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + Modal.close(() => setShowConfirmDeleteModal(true)); + }} wrapperStyle={[styles.pv3, styles.ph5, !shouldUseNarrowLayout ? styles.sidebarPopover : {}]} /> From c1b09aff61a6ad91b52ec85bb1ef316e8af40c74 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 17:01:34 +0530 Subject: [PATCH 10/31] Payment method menuitems --- src/pages/settings/Wallet/WalletPage/WalletPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 66f7772eb184..67da6ca7e4e5 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -566,6 +566,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { icon={Expensicons.Mail} onPress={() => { if (isActingAsDelegate) { + hideDefaultDeleteMenu(); setIsNoDelegateAccessMenuVisible(true); return; } @@ -580,6 +581,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { icon={Expensicons.Trashcan} onPress={() => { if (isActingAsDelegate) { + hideDefaultDeleteMenu(); setIsNoDelegateAccessMenuVisible(true); return; } From 6b746596504b77bb9630de7edcc47ea1a3593032 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 17:03:06 +0530 Subject: [PATCH 11/31] Delegate menu items --- .../settings/Security/SecuritySettingsPage.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index f646725319b3..2ee9af9630c9 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -21,7 +21,6 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -67,8 +66,6 @@ function SecuritySettingsPage() { const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); - // const [account] = useOnyx(ONYXKEYS.ACCOUNT); - // const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const setMenuPosition = useCallback(() => { if (!delegateButtonRef.current) { return; @@ -137,7 +134,7 @@ function SecuritySettingsPage() { link: '', wrapperStyle: [styles.sectionMenuItemTopDescription], })); - }, [translate, waitForNavigate, styles]); + }, [translate, waitForNavigate, styles, isActingAsDelegate]); const delegateMenuItems: MenuItemProps[] = useMemo( () => @@ -302,8 +299,12 @@ function SecuritySettingsPage() { title={translate('delegate.changeAccessLevel')} icon={Expensicons.Pencil} onPress={() => { - Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE.getRoute(selectedDelegate?.email ?? '', selectedDelegate?.role ?? '')); setShouldShowDelegatePopoverMenu(false); + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE.getRoute(selectedDelegate?.email ?? '', selectedDelegate?.role ?? '')); setSelectedDelegate(undefined); }} wrapperStyle={[styles.pv3, styles.ph5, !shouldUseNarrowLayout ? styles.sidebarPopover : {}]} @@ -314,6 +315,10 @@ function SecuritySettingsPage() { onPress={() => Modal.close(() => { setShouldShowDelegatePopoverMenu(false); + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } setShouldShowRemoveDelegateModal(true); }) } From c0959723544b62dff1ece709906674100276d3e2 Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 17:09:56 +0530 Subject: [PATCH 12/31] Dependent cleanup --- src/components/MoneyReportHeader.tsx | 3 +-- src/components/ReportActionItem/ReportPreview.tsx | 3 +-- .../ReportActionCompose/AttachmentPickerWithMenuItems.tsx | 3 +-- src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx | 5 ++--- src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx | 5 ----- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 3caf7a15d50e..bd9a368c975a 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -173,7 +173,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const isAnyTransactionOnHold = ReportUtils.hasHeldExpenses(moneyRequestReport?.reportID); const displayedAmount = isAnyTransactionOnHold && canAllowSettlement ? nonHeldAmount : formattedAmount; const isMoreContentShown = shouldShowNextStep || shouldShowStatusBar || (shouldShowAnyButton && shouldUseNarrowLayout); - const {isDelegateAccessRestricted, delegatorEmail} = useDelegateUserDetails(); + const {isDelegateAccessRestricted} = useDelegateUserDetails(); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const isReportInRHP = isReportOpenInRHP(navigationRef?.getRootState()); @@ -493,7 +493,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea setIsNoDelegateAccessMenuVisible(false)} - delegatorEmail={delegatorEmail ?? ''} /> setIsPaidAnimationRunning(false), []); @@ -588,7 +588,6 @@ function ReportPreview({ setIsNoDelegateAccessMenuVisible(false)} - delegatorEmail={delegatorEmail ?? ''} /> {isHoldMenuVisible && !!iouReport && requestType !== undefined && ( diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx index 27ab62a0f02e..fc2a5cbcff9d 100644 --- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx +++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx @@ -122,7 +122,7 @@ function AttachmentPickerWithMenuItems({ const {translate} = useLocalize(); const {windowHeight, windowWidth} = useWindowDimensions(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const {isDelegateAccessRestricted, delegatorEmail} = useDelegateUserDetails(); + const {isDelegateAccessRestricted} = useDelegateUserDetails(); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`); const {canUseCombinedTrackSubmit} = usePermissions(); @@ -346,7 +346,6 @@ function AttachmentPickerWithMenuItems({ setIsNoDelegateAccessMenuVisible(false)} - delegatorEmail={delegatorEmail ?? ''} /> ); diff --git a/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx index dac36a15cefd..16e98513a13b 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx @@ -13,7 +13,6 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; -import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; @@ -33,8 +32,8 @@ function ContactMethodsPage({route}: ContactMethodsPageProps) { const [session] = useOnyx(ONYXKEYS.SESSION); const loginNames = Object.keys(loginList ?? {}); const navigateBackTo = route?.params?.backTo; - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; + + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); // Sort the login names by placing the one corresponding to the default contact method as the first item before displaying the contact methods. diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index d23af0371ef3..b8ef3d2c198b 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -22,7 +22,6 @@ import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber'; import * as UserUtils from '@libs/UserUtils'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -43,8 +42,6 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) { const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const loginData = loginList?.[pendingContactAction?.contactMethod ?? contactMethod]; const validateLoginError = ErrorUtils.getLatestErrorField(loginData, 'addedLogin'); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE; @@ -111,7 +108,6 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) { }, [navigateBackTo]); return ( - // loginInputRef.current?.focus()} @@ -177,7 +173,6 @@ function NewContactMethodPage({route}: NewContactMethodPageProps) { /> - // ); } From cb314b3b87853bd65e5c0c7c7153e576c2c94c7b Mon Sep 17 00:00:00 2001 From: Sachin Chavda Date: Wed, 13 Nov 2024 18:02:39 +0530 Subject: [PATCH 13/31] SubscriptionPage --- .../CardSectionDataEmpty/index.tsx | 35 ++++++++++++++----- .../index.tsx | 34 +++++++++++++----- .../SubscriptionDetails/index.tsx | 13 ++++++- .../SubscriptionSettings/index.tsx | 17 ++++++++- .../SubscriptionSize/substeps/Size.tsx | 24 +++++++++++-- 5 files changed, 101 insertions(+), 22 deletions(-) diff --git a/src/pages/settings/Subscription/CardSection/CardSectionDataEmpty/index.tsx b/src/pages/settings/Subscription/CardSection/CardSectionDataEmpty/index.tsx index 627556e7b5bd..79a200c4772c 100644 --- a/src/pages/settings/Subscription/CardSection/CardSectionDataEmpty/index.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSectionDataEmpty/index.tsx @@ -1,26 +1,43 @@ -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; +import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; +import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@navigation/Navigation'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; function CardSectionDataEmpty() { const {translate} = useLocalize(); const styles = useThemeStyles(); + const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => account?.delegatedAccess?.delegate}); + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const openAddPaymentCardScreen = useCallback(() => { Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD); }, []); - + const handleAddPaymentCardPress = () => { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + openAddPaymentCardScreen(); + }; return ( -