From 4985eb311e29434750197ce849219006e2f20d18 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Mon, 18 Nov 2024 15:43:20 -0500 Subject: [PATCH 1/5] update updatedelegaterolepage to not found if logged in and deeplinked --- .../Security/SecuritySettingsPage.tsx | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index ac66c368f631..f725c4f9c960 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'; @@ -50,6 +52,8 @@ function SecuritySettingsPage() { const [account] = useOnyx(ONYXKEYS.ACCOUNT); const delegateButtonRef = useRef(null); + const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + const {delegatorEmail} = useDelegateUserDetails(); const [shouldShowDelegatePopoverMenu, setShouldShowDelegatePopoverMenu] = useState(false); const [shouldShowRemoveDelegateModal, setShouldShowRemoveDelegateModal] = useState(false); @@ -202,6 +206,28 @@ function SecuritySettingsPage() { [delegators, styles, translate, personalDetails], ); + const onUpdateDelegateRoleButtonPress = useCallback(() => { + if (isActingAsDelegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE.getRoute(selectedDelegate?.email ?? '', selectedDelegate?.role ?? '')); + setShouldShowDelegatePopoverMenu(false); + setSelectedDelegate(undefined); + }, [isActingAsDelegate, selectedDelegate]); + + const onRemoveDelegateButtonPress = useCallback(() => { + if (isActingAsDelegate && selectedDelegate?.email !== account?.delegatedAccess?.delegate) { + setIsNoDelegateAccessMenuVisible(true); + return; + } + + Modal.close(() => { + setShouldShowDelegatePopoverMenu(false); + setShouldShowRemoveDelegateModal(true); + }); + }, [account?.delegatedAccess?.delegate, isActingAsDelegate, selectedDelegate?.email]); + return ( { - Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE.getRoute(selectedDelegate?.email ?? '', selectedDelegate?.role ?? '')); - setShouldShowDelegatePopoverMenu(false); - setSelectedDelegate(undefined); - }} + onPress={onUpdateDelegateRoleButtonPress} wrapperStyle={[styles.pv3, styles.ph5, !shouldUseNarrowLayout ? styles.sidebarPopover : {}]} /> - Modal.close(() => { - setShouldShowDelegatePopoverMenu(false); - setShouldShowRemoveDelegateModal(true); - }) - } + onPress={onRemoveDelegateButtonPress} wrapperStyle={[styles.pv3, styles.ph5, !shouldUseNarrowLayout ? styles.sidebarPopover : {}]} /> @@ -330,6 +347,11 @@ function SecuritySettingsPage() { shouldShowCancelButton /> + setIsNoDelegateAccessMenuVisible(false)} + delegatorEmail={delegatorEmail ?? ''} + /> )} From 57d72c6fff583dd6fbfe984ebbb68151cf1923f3 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Mon, 18 Nov 2024 15:44:05 -0500 Subject: [PATCH 2/5] show DelegateNoAccessModal on disallowed activities --- .../UpdateDelegateRolePage.tsx | 83 ++++++++++--------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx index 1ac362a50457..824de09cd26a 100644 --- a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateRolePage.tsx @@ -1,5 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useState} from 'react'; +import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; @@ -11,7 +12,9 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {clearDelegateRolePendingAction, requestValidationCode, updateDelegateRoleOptimistically} from '@libs/actions/Delegate'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {DelegateRole} from '@src/types/onyx/Account'; @@ -22,6 +25,8 @@ function UpdateDelegateRolePage({route}: UpdateDelegateRolePageProps) { const {translate} = useLocalize(); const login = route.params.login; const [currentRole, setCurrentRole] = useState(route.params.currentRole); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const styles = useThemeStyles(); const roleOptions = Object.values(CONST.DELEGATE_ROLE).map((role) => ({ @@ -39,46 +44,48 @@ function UpdateDelegateRolePage({route}: UpdateDelegateRolePageProps) { }, [login]); return ( - - Navigation.goBack()} - /> - - <> - {translate('delegate.accessLevelDescription')}{' '} - - {translate('common.learnMore')} - - - - } - onSelectRow={(option) => { - if (option.isSelected) { - Navigation.dismissModal(); - return; + + + Navigation.goBack()} + /> + + <> + {translate('delegate.accessLevelDescription')}{' '} + + {translate('common.learnMore')} + + + } + onSelectRow={(option) => { + if (option.isSelected) { + Navigation.dismissModal(); + return; + } - requestValidationCode(); - setCurrentRole(option.value); - Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE_MAGIC_CODE.getRoute(login, option.value)); - }} - sections={[{data: roleOptions}]} - ListItem={RadioListItem} - /> - + requestValidationCode(); + setCurrentRole(option.value); + Navigation.navigate(ROUTES.SETTINGS_UPDATE_DELEGATE_ROLE_MAGIC_CODE.getRoute(login, option.value)); + }} + sections={[{data: roleOptions}]} + ListItem={RadioListItem} + /> + + ); } From 081996d01e6782a4b1fb4cf95d89315e9fe73552 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Mon, 18 Nov 2024 15:49:47 -0500 Subject: [PATCH 3/5] block magic code page too --- .../UpdateDelegateMagicCodePage.tsx | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateMagicCodePage.tsx b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateMagicCodePage.tsx index 3bc82e8d7e65..38ca40a95ca8 100644 --- a/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateMagicCodePage.tsx +++ b/src/pages/settings/Security/AddDelegate/UpdateDelegateRole/UpdateDelegateMagicCodePage.tsx @@ -9,6 +9,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -21,6 +22,7 @@ type UpdateDelegateMagicCodePageProps = StackScreenProps; @@ -44,28 +46,30 @@ function UpdateDelegateMagicCodePage({route}: UpdateDelegateMagicCodePageProps) }; return ( - - {({safeAreaPaddingBottomStyle}) => ( - <> - - {translate('delegate.enterMagicCodeUpdate', {contactMethod: account?.primaryLogin ?? ''})} - - - )} - + + + {({safeAreaPaddingBottomStyle}) => ( + <> + + {translate('delegate.enterMagicCodeUpdate', {contactMethod: account?.primaryLogin ?? ''})} + + + )} + + ); } From 41c92c8e7440ec734e7393cc4e99f133e5958bdf Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Tue, 26 Nov 2024 16:04:23 -0500 Subject: [PATCH 4/5] add blocks for other deeplinked delegate pages --- .../Security/AddDelegate/AddDelegatePage.tsx | 49 ++++++------ .../AddDelegate/ConfirmDelegatePage.tsx | 79 ++++++++++--------- .../AddDelegate/DelegateMagicCodeModal.tsx | 26 +++--- .../AddDelegate/SelectDelegateRolePage.tsx | 73 +++++++++-------- 4 files changed, 125 insertions(+), 102 deletions(-) diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 6f54fc098633..d5e70c46171d 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -13,6 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActions from '@libs/actions/Report'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -78,6 +79,8 @@ function AddDelegatePage() { const styles = useThemeStyles(); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); const {userToInvite, recentReports, personalDetails, searchValue, debouncedSearchValue, setSearchValue, headerMessage, areOptionsInitialized} = useOptions(); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const sections = useMemo(() => { const sectionsList = []; @@ -125,29 +128,31 @@ function AddDelegatePage() { }, [debouncedSearchValue]); return ( - - Navigation.goBack()} - /> - - + + Navigation.goBack()} /> - - + + + + + ); } diff --git a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx index 8dd3996a769a..8ec85c63d63f 100644 --- a/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/ConfirmDelegatePage.tsx @@ -1,5 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useState} from 'react'; +import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import Button from '@components/Button'; import HeaderPageLayout from '@components/HeaderPageLayout'; @@ -14,7 +15,9 @@ import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import DelegateMagicCodeModal from './DelegateMagicCodeModal'; @@ -28,6 +31,8 @@ function ConfirmDelegatePage({route}: ConfirmDelegatePageProps) { const login = route.params.login; const role = route.params.role as ValueOf; const showValidateActionModal = route.params.showValidateActionModal === 'true'; + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const {isOffline} = useNetwork(); const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(showValidateActionModal ?? false); @@ -50,42 +55,44 @@ function ConfirmDelegatePage({route}: ConfirmDelegatePageProps) { ); return ( - Navigation.goBack(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(login, role))} - title={translate('delegate.addCopilot')} - testID={ConfirmDelegatePage.displayName} - footer={submitButton} - childrenContainerStyles={[styles.pt3, styles.gap6]} - > - {translate('delegate.confirmCopilot')} - - Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(login, role))} - shouldShowRightIcon - /> - { - if (!showValidateActionModal) { - setIsValidateCodeActionModalVisible(false); - return; - } - Navigation.navigate(ROUTES.SETTINGS_SECURITY); - }} - isValidateCodeActionModalVisible={isValidateCodeActionModalVisible} - /> - + + Navigation.goBack(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(login, role))} + title={translate('delegate.addCopilot')} + testID={ConfirmDelegatePage.displayName} + footer={submitButton} + childrenContainerStyles={[styles.pt3, styles.gap6]} + > + {translate('delegate.confirmCopilot')} + + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_ROLE.getRoute(login, role))} + shouldShowRightIcon + /> + { + if (!showValidateActionModal) { + setIsValidateCodeActionModalVisible(false); + return; + } + Navigation.navigate(ROUTES.SETTINGS_SECURITY); + }} + isValidateCodeActionModalVisible={isValidateCodeActionModalVisible} + /> + + ); } diff --git a/src/pages/settings/Security/AddDelegate/DelegateMagicCodeModal.tsx b/src/pages/settings/Security/AddDelegate/DelegateMagicCodeModal.tsx index 6c108403c36b..bfbe7576d503 100644 --- a/src/pages/settings/Security/AddDelegate/DelegateMagicCodeModal.tsx +++ b/src/pages/settings/Security/AddDelegate/DelegateMagicCodeModal.tsx @@ -6,6 +6,7 @@ import useLocalize from '@hooks/useLocalize'; import * as User from '@libs/actions/User'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Delegate from '@userActions/Delegate'; import type CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -21,6 +22,7 @@ type DelegateMagicCodeModalProps = { function DelegateMagicCodeModal({login, role, onClose, isValidateCodeActionModalVisible}: DelegateMagicCodeModalProps) { const {translate} = useLocalize(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const isActingAsDelegate = !!account?.delegatedAccess?.delegate; const currentDelegate = account?.delegatedAccess?.delegates?.find((d) => d.email === login); const addDelegateErrors = account?.delegatedAccess?.errorFields?.addDelegate?.[login]; @@ -47,17 +49,19 @@ function DelegateMagicCodeModal({login, role, onClose, isValidateCodeActionModal }; return ( - User.requestValidateCodeAction()} - hasMagicCodeBeenSent={!!currentDelegate?.validateCodeSent} - handleSubmitForm={(validateCode) => Delegate.addDelegate(login, role, validateCode)} - descriptionPrimary={translate('delegate.enterMagicCode', {contactMethod: account?.primaryLogin ?? ''})} - /> + + User.requestValidateCodeAction()} + hasMagicCodeBeenSent={!!currentDelegate?.validateCodeSent} + handleSubmitForm={(validateCode) => Delegate.addDelegate(login, role, validateCode)} + descriptionPrimary={translate('delegate.enterMagicCode', {contactMethod: account?.primaryLogin ?? ''})} + /> + ); } diff --git a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx index 4270441775cd..fb741947a88a 100644 --- a/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx +++ b/src/pages/settings/Security/AddDelegate/SelectDelegateRolePage.tsx @@ -1,5 +1,6 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; +import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; @@ -10,7 +11,9 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -19,6 +22,8 @@ type SelectDelegateRolePageProps = StackScreenProps ({ @@ -30,39 +35,41 @@ function SelectDelegateRolePage({route}: SelectDelegateRolePageProps) { })); return ( - - Navigation.goBack(ROUTES.SETTINGS_ADD_DELEGATE)} - /> - role.isSelected)?.keyForList} - shouldUpdateFocusedIndex - headerContent={ - - <> - {translate('delegate.accessLevelDescription')}{' '} - - {translate('common.learnMore')} - - - - } - onSelectRow={(option) => { - Navigation.navigate(ROUTES.SETTINGS_DELEGATE_CONFIRM.getRoute(login, option.value)); - }} - sections={[{data: roleOptions}]} - ListItem={RadioListItem} - /> - + + + Navigation.goBack(ROUTES.SETTINGS_ADD_DELEGATE)} + /> + role.isSelected)?.keyForList} + shouldUpdateFocusedIndex + headerContent={ + + <> + {translate('delegate.accessLevelDescription')}{' '} + + {translate('common.learnMore')} + + + + } + onSelectRow={(option) => { + Navigation.navigate(ROUTES.SETTINGS_DELEGATE_CONFIRM.getRoute(login, option.value)); + }} + sections={[{data: roleOptions}]} + ListItem={RadioListItem} + /> + + ); } From fc7f5d67836e6a85cc192655e69c1fd023e63a7a Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Tue, 3 Dec 2024 12:42:22 -0500 Subject: [PATCH 5/5] close popup --- src/pages/settings/Security/SecuritySettingsPage.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index f725c4f9c960..75f11e4e90c8 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -349,7 +349,10 @@ function SecuritySettingsPage() { setIsNoDelegateAccessMenuVisible(false)} + onClose={() => { + setIsNoDelegateAccessMenuVisible(false); + setShouldShowDelegatePopoverMenu(false); + }} delegatorEmail={delegatorEmail ?? ''} />